DFS

图上的DFS

  • isVisited
  • for(row){ for(column){ helper()}}

构建图

694. Number of Distinct Islands

Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water.

Count the number of distinct islands. An island is considered to be the same as another if and only if one island can be translated (and not rotated or reflected) to equal the other.

Example 1:
11000
11000
00011
00011
Given the above grid map, return 1.
Example 2:
11011
10000
00001
11011
Given the above grid map, return 3

有什么方法表示一个路径的形状。注意要使用backtracking的思路,加上back


class Solution {
    static int[] dx = {-1, 0, 0, 1};
    static int[] dy = {0, 1, -1, 0};
    public int numDistinctIslands(int[][] grid) {
        if(grid == null || grid.length == 0) return 0;
        Set<String> set = new HashSet<>();
        int islands = 0;
        for(int i = 0;i < grid.length;i++) {
            for(int j = 0;j < grid[i].length;j++) {
                if(grid[i][j] == 1) {
                    StringBuilder temp = new StringBuilder();
                    temp.append('o');
                    explore(grid,i,j, temp);
                    if (!set.contains(temp.toString())) {
                        set.add(temp.toString());
                        islands++;
                    }
                }
            }
        }
        return islands;
    }
    public static void explore(int[][] grid, int i, int j, StringBuilder temp) {
        grid[i][j] = 0;
        for(int d = 0;d < dx.length; d++) {
            if(i+dy[d]<grid.length && i+dy[d]>=0 && j+dx[d]<grid[0].length && j+dx[d]>=0 && grid[i+dy[d]][j+dx[d]]==1) {
                temp.append(String.valueOf(d));
                explore(grid,i + dy[d], j + dx[d], temp);
                temp.append("b");
            }
        }
    }
}

399. Evaluate Division

构建weighted and directed的图,再用一个hashmap记录weight

742. Closest Leaf in a Binary Tree

Input:
root = [1, 3, 2], k = 1
Diagram of binary tree:
1
/
3 2

Output: 2 (or 3)
给一个数值代表一个node,找出离这个node的最近的叶子节点

首先要找到该节点,再找到距离叶子节点的最短路径。把树转换成一个无向图来做,用dfs建图找点,用BFS找最短路径。
start要声明为全局变量才行
Explanation: Either 2 or 3 is the nearest leaf node to the target of 1.

class Solution {
    TreeNode start = null;
    public int findClosestLeaf(TreeNode root, int k) {
        // key is node, list of its neighbours (parent, left, right children)
        Map<TreeNode, List<TreeNode>> map = new HashMap<>();
        // TreeNode start = null;
        // undirected graph
        helper(map, root, null, k);
        // bfs find shortest path to any leaf node
        Queue<TreeNode> queue = new LinkedList<>();
        Set<TreeNode> visited = new HashSet<>();
        if (start == null) return -2;
        queue.offer(start); 
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll(); 
            // is a leaf node 
            if (cur.right == null && cur.left == null) {
                return cur.val;
            }
            // visited
            visited.add(cur);
            
            for (TreeNode n : map.get(cur)) {
                if (!visited.contains(n)) {
                    queue.add(n);
                }
            }            
        }
        return -1;
    }
    // find k and construct the undirected map 
    public void helper(Map<TreeNode, List<TreeNode>> map, TreeNode root, TreeNode parent, int k) {
        if (root == null) return;
        if (root.val == k) {
            start = root;
        }
        if (parent != null) {
            if (!map.containsKey(parent)) {
                map.put(parent, new ArrayList<>());
            }
            if (!map.containsKey(root)) {
                map.put(root, new ArrayList<>());
            }
            map.get(parent).add(root);
            map.get(root).add(parent);
        }
        helper(map, root.left, root, k);
        helper(map, root.right, root, k);
    }
}

737. Sentence Similarity II

Given two sentences words1, words2 (each represented as an array of strings), and a list of similar word pairs pairs, determine if two sentences are similar.

For example, words1 = ["great", "acting", "skills"] and words2 = ["fine", "drama", "talent"] are similar, if the similar word pairs are pairs = [["great", "good"], ["fine", "good"], ["acting","drama"], ["skills","talent"]].

Note that the similarity relation is transitive. For example, if "great" and "good" are similar, and "fine" and "good" are similar, then "great" and "fine" are similar.

Similarity is also symmetric. For example, "great" and "fine" being similar is the same as "fine" and "great" being similar.

Also, a word is always similar with itself. For example, the sentences words1 = ["great"], words2 = ["great"], pairs = [] are similar, even though there are no specified similar word pairs.

Finally, sentences can only be similar if they have the same number of words. So a sentence like words1 = ["great"] can never be similar to words2 = ["doubleplus","good"].

Pair是可以传递的,想到构建图,搜索图,优化的话需要预处理,给每一个连通分量一个ID
1 如何建图 2 区别有向图和无向图 3 情况考虑全面,如果单词相等跳过,如果单词不再pair里,直接返回false

    public boolean areSentencesSimilarTwo(String[] words1, String[] words2, String[][] pairs) {
        if (words1.length != words2.length) {
            return false;
        }
        // construct a map by pairs using dfs
        // key word, value the word's neighbours, is an undirected graph
        Map<String, Set<String>> map = new HashMap<>();
        for (String[] pair : pairs) {
            if (map.containsKey(pair[0])) {
                map.get(pair[0]).add(pair[1]);
            } else {
                Set<String> set = new HashSet<>();
                set.add(pair[1]);
                map.put(pair[0], set);
            }
            if (map.containsKey(pair[1])) {
                map.get(pair[1]).add(pair[0]);
            } else {
                Set<String> set = new HashSet<>();
                set.add(pair[0]);
                map.put(pair[1], set);
            }
        }
        for (int i = 0; i < words1.length; i++) {
            // case 1
            if (words1[i].equals(words2[i])) {
                continue;
            }
            if (!helper(words1[i], words2[i], map, new HashSet<>())) {
                return false;
            }
        }
        return true;
    }
    public boolean helper(String source, String target, Map<String, Set<String>> map, Set<String> visited) {
        if (!map.containsKey(source)) {
            return false;
        }
        if (map.get(source).contains(target)) {
            return true;
        }
        Set<String> temp = map.get(source);
        visited.add(source);
        for (String str : temp) {
            if(!visited.contains(str) && helper(str, target, map, visited)) {
                return true;
            }
        }
        return false;
    }

212. Word Search II

给一个char的矩阵和单词list,找出list中在矩阵中的单词
Given a 2D board and a list of words from the dictionary, find all words in the board.

Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.

For example,
Given words = ["oath","pea","eat","rain"] and board =

[
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
Return ["eat","oath"].

注意isVisited。先temp+board[i][j]就不用考虑trie里是否包含空字符串的情况了。字符串不用deep copy

public class Solution {
    Set<String> res = new HashSet<>();
    public List<String> findWords(char[][] board, String[] words) {
        // construct a trie
        Trie trie = new Trie();
        for (String word : words) {
            trie.insert(word);
        }
        
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                helper(i, j, trie, "", board);
            }
        }
        return new ArrayList<String>(res);
    }
    
    public void helper(int i, int j, Trie trie, String temp, char[][] board) {
        // out of bound
        if (i < 0 || i > board.length -1 || j < 0 || j > board[0].length - 1) {
            return;
        }
        // if visited
        if (board[i][j] == '#') {
            return;
        }
        temp = temp + board[i][j];
        if (!trie.startWith(temp)) {
            return;
        }
        // if in trie, add to res
        if (trie.search(temp)) {
            res.add(temp);
        }
        int[] directionX = {0, 0, 1, -1};
        int[] directionY = {1, -1, 0, 0};
        for (int k = 0; k < 4; k++) {
            char cur = board[i][j];
            board[i][j] = '#';
            helper(i + directionX[k], j + directionY[k], trie, temp, board);
            board[i][j] = cur;
        }
    }
}

286. Walls and Gates

-1 - A wall or an obstacle.
0 - A gate.
INF - Infinity means an empty room.
For example, given the 2D grid:
INF -1 0 INF
INF INF INF -1
INF -1 INF -1
0 -1 INF INF
After running your function, the 2D grid should be:
3 -1 0 1
2 2 1 -1
1 -1 2 -1
0 -1 3 4

DFS BFS都可以做,需要注意的是以门为起点去向下延伸,而不是以房间开始

public void wallsAndGates(int[][] rooms) {
    for (int i = 0; i < rooms.length; i++)
        for (int j = 0; j < rooms[0].length; j++)
            if (rooms[i][j] == 0) dfs(rooms, i, j, 0);
}

private void dfs(int[][] rooms, int i, int j, int d) {
  // 注意rooms[i][j] < d
    if (i < 0 || i >= rooms.length || j < 0 || j >= rooms[0].length || rooms[i][j] < d) return;
    rooms[i][j] = d;
    dfs(rooms, i - 1, j, d + 1);
    dfs(rooms, i + 1, j, d + 1);
    dfs(rooms, i, j - 1, d + 1);
    dfs(rooms, i, j + 1, d + 1);
}

200. Number of Islands

给一个二维数组算岛屿的数量,有多少个连着的1

遍历二维数组,发现1之后调用helper函数向四周扩展一步,并把该位置的1换成0。
再发现1,再次调用helper
注意越界的情况 可以写一个单独的函数inbound判断

    static int[] dx = {-1,0,0,1};
    static int[] dy = {0,1,-1,0};
    public static int numIslands(char[][] grid) {
        if(grid==null || grid.length==0) return 0;
        int islands = 0;
        for(int i=0;i<grid.length;i++) {
            for(int j=0;j<grid[i].length;j++) {
                if(grid[i][j]=='1') {
                    explore(grid,i,j);
                    islands++;
                }
            }
        }
        return islands;
    }
    public static void explore(char[][] grid, int i, int j) {
        grid[i][j]='0';
        for(int d=0;d<dx.length;d++) {
            if(i+dy[d]<grid.length && i+dy[d]>=0 && j+dx[d]<grid[0].length && j+dx[d]>=0 && grid[i+dy[d]][j+dx[d]]=='1') {
                explore(grid,i+dy[d],j+dx[d]);
            }
        }
    }

DFS + Backtracking + 剪枝

22. Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

For example, given n = 3, a solution set is:

[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]

注意stringbuilder如何backtrack的

public List<String> generateParenthesis(int n) {
     List<String> res = new ArrayList<>();
     helper(res, new StringBuilder(), 0, 0, n);
     return res;
}

private void helper(List<String> res, StringBuilder sb, int open, int close, int n) {
    if(open == n && close == n) {
        res.add(sb.toString());
        return;
    }
    
    if(open < n) {
        sb.append("(");
        helper(res, sb, open+1, close, n);
        sb.setLength(sb.length()-1);
    } 
    if(close < open) {
        sb.append(")");
        helper(res, sb, open, close+1, n);
        sb.setLength(sb.length()-1);
    }
}

301. Remove Invalid Parentheses

给一个String ()()()),移除最少的invalid括号使string valid

和上一题一样,需要遍历所有可能性,所以用dfs + backtracking,有一个地方可以剪枝就是观察String,保证剩下的最长就需要让删除的少,发现最少删除一个右括号就可以使其valid,所以把最少删除的右括号和左括号的数量作为参数传入DFS中
可以尝试画递归树,题目说删东西不要一味想去remove,也可以是建空白的往里加

class Solution {
   public List<String> removeInvalidParentheses(String s) {
       Set<String> res = new HashSet<>();
       if (s == null || s.length() == 0) {
           return new ArrayList<String>();
       }
       // remove maximum number of right or left, otherwise the dfs will try all the possibilities
       int maxRight = 0, maxLeft = 0;
       for (char c : s.toCharArray()) {
           if (c == '(') {
               maxLeft++;
           } else if (c == ')') {
               if (maxLeft == 0) {
                   maxRight++;;
               } else {
                   maxLeft--;
               }
           } else {
              // ignore 
           }
       }
       helper(s, 0, new StringBuilder(), res, maxLeft, maxRight, 0);
       return new ArrayList<String>(res);
   }
   public void helper(String s, int index, StringBuilder temp, Set<String> res, int maxLeft, int maxRight, int count) {
       // base case
       if (index == s.length()) {
           if (count == 0 && maxLeft == 0 && maxRight == 0) {
               res.add(temp.toString());
           }  
           return;
       }

       if (maxLeft < 0 || maxRight < 0 || count < 0) {
           return;
       }
       char cur = s.charAt(index);
       int len = temp.length();
       if (cur == '(') {
           helper(s, index + 1, temp.append('('), res, maxLeft, maxRight, count + 1); // keep
           helper(s, index + 1, temp, res, maxLeft - 1, maxRight, count); // delete a (
       } else if (cur == ')') {
           helper(s, index + 1, temp.append(')'), res, maxLeft, maxRight, count - 1);
           helper(s, index + 1, temp, res, maxLeft, maxRight - 1, count); // delete a )           
       } else {
           helper(s, index + 1, temp.append(cur), res, maxLeft, maxRight, count);
       }
       // backtracking
       temp.setLength(len);
   }
}

17. Letter Combinations of a Phone Number

手机键盘输入数字,计算出所有组合的可能性

有“所有”出现,想到穷举,dfs
dfs的核心是helper函数的传入参数,传入:当前的组合String temp,结果ArrayList of String,输入字符串处理到第几位的index

Word Search

140. Word Break II

s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].
A solution is ["cats and dog", "cat sand dog"].

DFS + Memo
注意base case的add(“”)

    public List<String> wordBreak(String s, List<String> wordDict) {
        if (s == null || s.length() == 0 || wordDict == null) {
            return null;
        }
        Map<String, List<String>> map = new HashMap<>();
        Set<String> set = new HashSet<>();
        for (String word : wordDict) {
            set.add(word);
        }
        return helper(s, set, map);
    }
    public List<String> helper(String s, Set<String> set, Map<String, List<String>> map) {
        List<String> res = new ArrayList<>();
        // find
        if (s.length() == 0) {
            // 区分什么都没找到的情况
            res.add("");
            return res;
        }
        if (map.containsKey(s)) return map.get(s);
        // 注意 i <=
        for (int i = 1; i <= s.length(); i++) {
            String sub = s.substring(0, i);
            if (set.contains(sub)) {
                List<String> temp = helper(s.substring(i, s.length()), set, map);
                if (temp.size() > 0) {
                    for (String word : temp) {
                        String s1 = sub + " " + word;
                        res.add(s1.trim());                 
                    }
                }
            }
        }
        map.put(s, res);
        return res;        
    }

425. Word Squares

找所有的square组合
Input:
["abat","baba","atan","atal"]
Output:
[
[ "baba",
"abat",
"baba",
"atan"
],
[ "baba",
"abat",
"baba",
"atal"
]
]

Trie + Backtracking + 剪枝
Trie 有一个不同的是加了一个startwith的list,方便找以指定字符串开头的所有字符串
1 根据temp的size找第几列,一开始没想明白
2 Trie的startWith字段

class Solution {
    public List<List<String>> wordSquares(String[] words) {
        List<List<String>> res = new ArrayList<>();
        if (words == null || words.length == 0) {
            return res;
        }
        Trie trie = new Trie(words);
        List<String> temp = new ArrayList<>();
        for (String word : words) {
            temp.add(word);
            helper(temp, res, trie, word.length());
            temp.remove(0);
        }
        return res;
    }
    
    public void helper(List<String> temp, List<List<String>> res, Trie trie, int len) {
        int size = temp.size();
        if (size == len) {
            res.add(new ArrayList<>(temp));
            return;
        }
        
        StringBuilder prefix = new StringBuilder();
        for (String s : temp) {
            if(size <= s.length() - 1) {
                 prefix.append(s.charAt(size));               
            } else {
                return;
            }
        }
        // backtracking
        List<String> candidates = trie.findByPrefix(prefix.toString());
        
        for (String c : candidates) {
            //if (!temp.contains(c)) {
                temp.add(c);
                helper(temp, res, trie, len);
                temp.remove(temp.size() - 1);               
            //}
        }
    }
}
class TrieNode {
    TrieNode[] children = new TrieNode[26];
    boolean isWord = false;
    List<String> startWith = new ArrayList<>();
    public TrieNode() {}
}
class Trie {
    TrieNode root;
    public Trie (String[] words) {
        root = new TrieNode();
        // add into trie
        for (String word : words) {
            insert(word);
        }
    }
    private void insert(String str) {
        TrieNode cur = root;
        for (char c : str.toCharArray()) {
            if (cur.children[c - 'a'] == null) {
                cur.children[c - 'a'] = new TrieNode();
            }
            cur.children[c - 'a'].startWith.add(str);
            cur = cur.children[c - 'a'];
        }
        cur.isWord = true;
    }
    public List<String> findByPrefix(String str) {
        TrieNode cur = root;
        for (char c : str.toCharArray()) {
            if (cur.children[c - 'a'] == null) {
                return list;
            }
            cur = cur.children[c - 'a'];
        }
        return cur.startWith;
    }
}

140. Word Break II

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. You may assume the dictionary does not contain duplicate words.

Return all such possible sentences.

For example, given
s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].

A solution is ["cats and dog", "cat sand dog"].

    public List<String> wordBreak(String s, List<String> wordDict) {
        if (s == null || s.length() == 0 || wordDict == null) {
            return null;
        }
        Map<String, List<String>> map = new HashMap<>();
        Set<String> set = new HashSet<>();
        for (String word : wordDict) {
            set.add(word);
        }
        return helper(s, set, map);
    }
    public List<String> helper(String s, Set<String> set, Map<String, List<String>> map) {
        List<String> res = new ArrayList<>();
        // find
        if (s.length() == 0) {
            // 区分什么都没找到的情况
            res.add("");
            return res;
        }
        if (map.containsKey(s)) return map.get(s);
        // 注意 i <=
        for (int i = 1; i <= s.length(); i++) {
            String sub = s.substring(0, i);
            if (set.contains(sub)) {
                List<String> temp = helper(s.substring(i, s.length()), set, map);
                if (temp.size() > 0) {
                    for (String word : temp) {
                        String s1 = sub + " " + word;
                        res.add(s1.trim());                 
                    }
                }
            }
        }
        map.put(s, res);
        return res;        
    }

DFS helper带返回值的情况

There is a box protected by a password. The password is n digits, where each letter can be one of the first k digits 0, 1, ..., k-1.
You can keep inputting the password, the password will automatically be matched against the last n digits entered.
For example, assuming the password is "345", I can open it when I type "012345", but I enter a total of 6 digits.
Please return any string of minimum length that is guaranteed to open the box after the entire string is inputted.
Example 2:
Input: n = 2, k = 2
Output: "00110"
Note: "01100", "10011", "11001" will be accepted too.

不需要遍历出所有的情况,有一种满足条件就退出,不满足再回溯
注意代码里的细节

class Solution {
    public String crackSafe(int n, int k) {
        int total = (int) (Math.pow(k, n));
        Set<String> visited = new HashSet<>();
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < n; i++) {
            res.append('0');
        }
        visited.add(res.toString());
        helper(total, visited, res, n, k);
        
        return res.toString();

    }
    public boolean helper(int total, Set<String> visited, StringBuilder res, int n, int k) {
        if (total == visited.size()) {
            return true;
        }
        // reuse the last n-1 digits
        // stringbuilder substring
        // 从 res拿出最后的 n-1 位 比如res XXXXX 需要一个n=3位的密码,所以从res中取出后两位,再加上新的一位构成新密码
        String prev = res.substring(res.length() - n + 1, res.length());
        // next step 0,1,2,3...
        for (int i = 0; i < k; i++) {
            String cur = prev + i;
            if (!visited.contains(cur)) {
                res.append(i); 
                visited.add(cur);
                if(helper(total, visited, res, n, k)) {
                    return true;
                }
                // backtracking
                visited.remove(cur);
                // stringbuilder delete last 
                res.delete(res.length() - 1, res.length());
            }
        }
        return false;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,376评论 0 23
  • 飞雪城广袤浩瀚,内也有山峰峡谷,像应山老母就占据了一片群山,建了洞府。 在一座峡谷中,东伯雪鹰、虫祖巴妥晨、剑主他...
    im喵小姐阅读 312评论 0 0
  • 想在一个夕阳西下的傍晚跑到你楼下,紧紧拥抱你,然后此生再也不找你。
    不与人知阅读 63评论 0 2
  • 现在要写的是一例被医院诊断为强直性脊椎炎的案例。患者年轻男性,几年前诊断为强直性脊椎炎。 第一次见到病人时,病人很...
    医难为阅读 1,099评论 0 0
  • 关于点赞 有一次一位不太熟的朋友发信息链接过来请帮忙点赞XX小朋友的艺术作品,是我的XX关系。我二话不说就点进去了...
    吉草末阅读 146评论 0 0