Tuesday, February 27, 2018

LeetCode 98 Validate Binary Search Tree

#**LeetCode98**
---
https://leetcode.com/problems/validate-binary-search-tree/description/

Yifeng Zeng

#题目描述
---
Validate Binary Search Tree

#思路报告
---

The first thing is to clarify the defination of the BST input. The BST has a very important property which is that the in-order traversal of a BST is a non-decreasing sequence or a increasing sequence (discuss this with the interviewer, LC uses increasing sequence). So the primitive idea is to do an in-order traversal of this TreeNode, and find if the current element is smaller than the previous element. If it is, then it is not a BST, otherwise it is.

The non-recursive code that I previous recite is this:

代码如下:
```java
public boolean isValidBST(TreeNode root) {
    if (root == null) {
        return true;
    }
    Deque<TreeNode> stack = new ArrayDeque<>();
    TreeNode cur = root;
    TreeNode prev = null;
    Boolean isFirst = true;

    while (!stack.isEmpty() || cur != null) {
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
        cur = stack.pop();
        if (isFirst) {
            prev = cur;
            isFirst = false;
        } else {
            if (cur.val <= prev.val) {
                return false;
            }
            prev = cur;
        }
        cur = cur.right;
    }

    return true;
}
```

From one of Qinyuan's lecture, the non-recursive code can be something like this, and the order can be any of pre/in/post-order. More details will be explained in the report of LC145 Binary Tree Postorder Traversal.

Code:
```java
class Pair {
    TreeNode node;
    boolean print;
    public Pair(TreeNode node, boolean print) {
        this.node = node;
        this.print = print;
    }
}

public boolean isValidBST(TreeNode root) {
    if (root == null) {
        return true;
    }

    Deque<Pair> stack = new ArrayDeque<>();
    stack.push(new Pair(root, false));
    boolean isFirst = true;
    TreeNode prev = null;

    while (!stack.isEmpty()) {
        Pair cur = stack.pop();
        if (cur.node == null) {
            continue;
        }

        if (cur.print) {
            if (isFirst) {
                isFirst = false;
            } else {
                if (cur.node.val <= prev.val) {
                    return false;
                }
            }
            prev = cur.node;
        } else {
            stack.push(new Pair(cur.node.right, false));
            stack.push(new Pair(cur.node, true));
            stack.push(new Pair(cur.node.left, false));
        }
    }

    return true;
}
```
We can also solve it without traversal. The defination is that all the left children has smaller values than the root value, all the right children has larger values than the root value and both left and right child is also a BST. Then for the current root, I can just see if the largest number in all the left children is smaller than the root value and see if the smallest number in all the right children is larger than the root value. So we can use divid and conquer. We need to see the smallest and largest number in the root's children so we might need a wrapper for return.

Code:
```java
class ReturnType {
    long max;
    long min;
    boolean isValid;
    public ReturnType(long max, long min, boolean isValid) {
        this.max = max;
        this.min = min;
        this.isValid = isValid;
    }
}

public boolean isValidBST(TreeNode root) {
    return helper(root).isValid;
}

private ReturnType helper(TreeNode root) {
    ReturnType res = new ReturnType(Long.MIN_VALUE, Long.MAX_VALUE, true);
    if (root == null) {
        return res;
    }

    res.min = root.val;
    res.max = root.val;

    ReturnType left = helper(root.left);
    ReturnType right = helper(root.right);

    res.isValid = left.isValid && right.isValid && left.max < root.val && root.val < right.min;

    res.min = Math.min(res.min, left.min);
    res.min = Math.min(res.min, right.min);
    res.max = Math.max(res.max, left.max);
    res.max = Math.max(res.max, right.max);

    return res;
}
```

#套路总结
---
- When starting to code, ask if root == null is true or false.
- The BST has a very important property which is that the in-order traversal of a BST is a non-decreasing sequence or a increasing sequence (LC uses increasing sequence).

LeetCode 16 3Sum Closest

#**LeetCode16**
---
https://leetcode.com/problems/3sum-closest/description/

Yifeng Zeng

#题目描述
---
3Sum Closest

#思路报告
---

LC167. Two Sum II - Input array is sorted的思路,左右两个指针,左右之和大于target,那么右边往左移使得sum变小,左右之和小于target,那么左边往右移使得sum变大。本题可以借鉴LC167的思路,3sum无非就是固定一个element,另外两个element像LC167那样移动去找target或者找closest target。那么我们先对数组排序,然后从左往右固定nums[i],那么其实就是在i后面找最接近target - nums[i]的two sum。也是大于target - nums[i]时,右边往左移使sum变小,小于target - nums[i]时,左边往右移使sum变大。取绝对值来保存different最小时的nums[i], nums[left], nums[right]的sum。

代码如下:
```java
public int threeSumClosest(int[] nums, int target) {
    if (nums == null || nums.length == 0) {
        throw new IllegalArgumentException("Invalid input");
    }

    Arrays.sort(nums);
    int diff = Integer.MAX_VALUE;
    int res = Integer.MAX_VALUE;
    for (int i = 0; i < nums.length - 2; i++) {
        int t = target - nums[i];
        int left = i + 1;
        int right = nums.length - 1;
        while (left < right) {
            int sum = nums[left] + nums[right] - t;
            if (Math.abs(sum) < diff) {
                diff = Math.abs(sum);
                res = sum + target;
            }
            if (sum > 0) {
                right--;
            } else {
                left++;
            }
        }
    }
    return res;
}
```


#套路总结
---
- 数组未排序没有好办法解的情况下可以考虑先排序。
- 多个数组合的情况可以考虑固定其中一个。

LeetCode 82 Remove Duplicates from Sorted List II

#**LeetCode82**
---
https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/description/

Yifeng Zeng

#题目描述
---
Remove Duplicates from Sorted List II

#思路报告
---

因为是sorted linked list,而且有重复要删除重复数字的所有node,那么意味着我们需要一个prev node来记录重复数字之前的那个node。而且第一个node就可能重复,所以我们需要一个dummy node来辅助。那么prev从dummy开始,用一前一后slow fast两个指针,只要slow fast的值相等那么fast向后移动直到不等,那么prev.next = fast就可以把所有重复的node remove掉了。如果slow fast都不相等,那么prev slow fast同时往后移一位。

代码如下:
```java
public ListNode deleteDuplicates(ListNode head) {
    if (head == null) {
        return head;
    }

    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode prev = dummy;
    ListNode slow = head;
    ListNode fast = head.next;
    while (fast != null) {
        while (fast != null && fast.val == slow.val) {
            fast = fast.next;
        }

        if (slow.next == fast) {
            prev = slow;
            slow = fast;
        } else if (slow.next != fast) {
            prev.next = fast;
            slow = fast;
        }
    }

    return dummy.next;
}
```


#套路总结
---
- 改变原list的话要借助dummy node。
- 在singly linked list里面remove掉某些node的话,需要prev。

LeetCode 57 Insert Interval

#**LeetCode57**
---
https://leetcode.com/problems/insert-interval/description/

Yifeng Zeng

#题目描述
---
Insert Interval

#思路报告
---

因为intervals已经排了序了,所以我们只需要把newInterval的start和end在这些intervals里面对应的位置找到就行了。由于是从小到大排序的,我们先看newInterval.start,我们遍历intervals,找到某一个intervals.get(i),当i.end < newInterval.start是我们把直接放到result里面,因为不会跟newInterval有overlap。这时我们有了第一个newInterval.start < i.end的情况,那么我们要考虑newInterval.start跟i.start的大小,两者取更小的作为newInterval的start即可。然后我们要找到这个newInterval跟哪些intervals.get(i)相overlap,那么其实只需要找到最后一个i.start小于等于newInterval.end的interval即可,那么更新newInterval.end为newInterval.end和i.end两者更大的即可。剩下后面的i.start都比newInterval.end要大,也不会有overlap,所以先把newInterval放进result里面,再把后面所有剩下的intervals放进result里面就可以了。

代码如下:
```java
public List<Interval> insert(List<Interval> intervals, Interval newInterval) {
    List<Interval> result = new ArrayList<>();

    int i = 0;
    while (i < intervals.size() && intervals.get(i).end < newInterval.start) {
        result.add(intervals.get(i));
        i++;
    }
    if (i < intervals.size()) {
        newInterval.start = Math.min(newInterval.start, intervals.get(i).start);
    }
    while (i < intervals.size() && intervals.get(i).start <= newInterval.end) {
        newInterval.end = Math.max(newInterval.end, intervals.get(i).end);
        i++;
    }
    result.add(newInterval);
    while (i < intervals.size()) {
        result.add(intervals.get(i));
        i++;
    }
    return result;
}
```


#套路总结
---
- 其实这个题就是对于一个复杂的问题拆分成多个简单问题的例子,每一个步骤单独看起来其实很简单,但是不容易从复杂问题想到,而且有一些corner case需要考虑,比如intervals的size为0的情况。

LeetCode 75 Sort Colors

#**LeetCode75**
---
https://leetcode.com/problems/sort-colors/description/

Yifeng Zeng

#题目描述
---
Sort Colors

#思路报告
---
拿到这个题最primitive的想法肯定是自己写一个quick sort/merge sort甚至直接调用Arrays.sort()。但这并没有利用到只有0,1,2三种color的特质,所以quick sort/merge sort明显就不再是考点了。既然我们已经知道了有固定3种颜色,那么我们可以用三个变量直接存一下每个颜色出现了多少次然后把每个颜色出现的次数对应回原array就可以了,这样的话可以做到时间O(n),空间O(3)的情况,但是说白了这个O(3)就是O(k),k是color的个数,而当k等于n时这是不太好的,那么我们可不可以省略这个O(k)的空间而保持O(n)的时间呢?在线性array上能做的不要extra space的inplace操作其实就只有swap,那么我们就考虑swap。而要O(n)的时间,肯定是多个(k个)指针,一个指针指向array里0在的那一整块,一个指针指向1的那一整块,一个指针指向2的那一整块。对于一个整块里面不属于它的element进行swap操作。

代码如下

```java
    public void sortColors(int[] nums) {
        if (nums == null || nums.length <= 1) {
            return;
        }
        int i = 0;
        int l = 0;
        int r = nums.length - 1;
        while (l <= r) {
            if (nums[l] == 0) {
                nums[l] = nums[i];
                nums[i] = 0;
                i++;
                l++;
            } else if (nums[l] == 1) {
                l++;
            } else if (nums[l] == 2) {
                nums[l] = nums[r];
                nums[r] = 2;
                r--;
            }
        }
    }
```

#套路总结
---
- array的inplace操作只能做swap,这个挺重要的,要有这个敏感度。

LeetCode 155 Min Stack

#**LeetCode155**
---
https://leetcode.com/problems/min-stack/description/

Yifeng Zeng

#题目描述
---
Min Stack

#思路报告
---
这个题是去年听太阁算法左程云老师的课讲的,当时没多想。后来仔细想一下其实挺straight forward的,要实现一个min stack那么stack本身的功能就用一个ArrayDeque作为stack来完成。那么min这个property肯定需要另外维护。什么数据结构最接近stack呢,肯定先想到stack本身,那么另外用一个stack(minStack)来维护min这个property可以不呢,当然可以。push的时候push当前整个stack里面最小的数就好,那么push进minStack时,peek minStack的值跟要push的x比较就好,因为peek minStack已经是整个stack里面最小的值了。x小就push x,否则push misStack.peek()。


代码如下

```java
class MinStack {

    Deque<Integer> dataStack;// = new ArrayDeque<>();
    Deque<Integer> minStack;// = new ArrayDeque<>();
    /** initialize your data structure here. */
    public MinStack() {
        dataStack = new ArrayDeque<>();
        minStack = new ArrayDeque<>();
    }

    public void push(int x) {
        dataStack.push(x);
        if (minStack.isEmpty() || minStack.peek() > x) {
            minStack.push(x);
        } else {
            minStack.push(minStack.peek());
        }
    }

    public void pop() {
        dataStack.pop();
        minStack.pop();
    }

    public int top() {
        return dataStack.peek();
    }

    public int getMin() {
        return minStack.peek();
    }
}
```

#套路总结
---
- 既然题目是设计min stack,那么先考虑把basic的stack功能用ArrayDeque实现,再考虑怎样维护min这个property。先考虑用跟stack有最接近性质的stack本身来维护min,那么只要保证每次push的是整个stack里面的最小值就可以了,pop的时候两个stack同时pop,getMin的时候peek minStack就好。

LeetCode 225 Implement Stack using Queues

#**LeetCode225**
---
https://leetcode.com/problems/implement-stack-using-queues/description/

Yifeng Zeng

#题目描述
---
Implement Stack using Queues

#思路报告
---
拿到这个题,先分析Stack和Queue的性质,stack是FILO,queue是FIFO,那么只放一个数(假设为1)进queue和进stack其实没有区别。那么再放第二个数(假设为2)的时候,先进的那个数1其实需要放到现在放的这个数2的后面,那么下一次从queue里面拿出来就可以先拿出2了。所以做push操作的时候我们用另外一个queue(help)把要push的数(前面提到的2)先暂存一下,然后把queue(真正的data)里面的数全部放入help queue,这样的顺序就是FILO了,再把help queue里面的数放回data queue以便下一次操作。那么做pop,top的时候只需要做data queue的poll,peek操作了。


代码如下

```java
class MyStack {

    Deque<Integer> dataQ;
    Deque<Integer> helpQ;
    /** Initialize your data structure here. */
    public MyStack() {
        dataQ = new LinkedList<>();
        helpQ = new LinkedList<>();
    }

    /** Push element x onto stack. */
    public void push(int x) {
        helpQ.offer(x);
        while (!dataQ.isEmpty()) {
            helpQ.offer(dataQ.poll());
        }
        while (!helpQ.isEmpty()) {
            dataQ.offer(helpQ.poll());
        }
    }

    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return dataQ.poll();
    }

    /** Get the top element. */
    public int top() {
        return dataQ.peek();
    }

    /** Returns whether the stack is empty. */
    public boolean empty() {
        return dataQ.isEmpty();
    }
}
```

#套路总结
---
- 这个貌似没感觉到有什么套路,既然题目是用queue implement stack,而一个queue明显不够用,就用两个queue,在想想stack queue操作顺序的不同就可以解出来了

LeetCode 56 Merge Intervals

#**LeetCode56**
---
https://leetcode.com/problems/merge-intervals/description/

Yifeng Zeng

#题目描述
---
Merge Intervals

#思路报告
---

如果要merge a list of intervals,我们首先想到的是在这个list里面选两个interval来merge,那么就是两个for循环,O(n^2)。对于每一对interval: i1,i2,我们要看i1.start是否在[i2.start, i2.end]之间,还要看i2.star是否在[i1.start, i1.end]之间。那么能不能提速呢?能不能只检查一半,即只检查i1.start是否在[i2.start, i2.end]之间呢?可以,只要我们保证i1.start >= i2.start就可以了。怎样保证呢?我们可以把所有的intervals按照i.start排序就好了,那么sort的时间就是O(nlogn)。所以我们要自己写一个Interval的comparator。那么假设intervals已经排好序了,我们还需要两个for循环做O(n^2)的时间吗?明显不用,我们只需要把第一个interval拿出来(假设为prev),作为一个base case,再拿后面的interval拿出来(假设为cur)跟它比较。因为我们已经排序了,所以一定有prev.start <= cur.start,那么我们只用检查cur.end是否小于等于pre.end,如果是,那么我们可以merge,如果不是,证明prev不会有其他的可以merge了,因为后面的i.start也一定大于等于pre.end。那么我们就可以把这个prev放在result里面了。但是我们要注意的是,最后一个prev,它将不再会有其他的interval跟它比较了,所以也要把它放到result里面,就刚跟LC186最后一个word类似。所以我们把merge的时间复杂度降到了O(n),但是排序用了O(nlogn),所以整个算法的时间复杂度是O(nlogn)。

代码如下:
```java
class Solution {
    Comparator<Interval> myComparator = new Comparator<Interval>() {
        @Override
        public int compare(Interval o1, Interval o2) {
            return o1.start - o2.start;
        }
    };
    public List<Interval> merge(List<Interval> intervals) {
        List<Interval> res = new ArrayList<>();
        if (intervals == null || intervals.size() == 0) {
            return res;
        }
        Collections.sort(intervals, myComparator);
        Interval prev = intervals.get(0);
        for (int i = 1; i < intervals.size(); i++) {
            Interval cur = intervals.get(i);
            if (cur.start <= prev.end) {
                prev.end = Math.max(prev.end, cur.end);
            } else {
                res.add(prev);
                prev = cur;
            }
        }
        res.add(prev);
        return res;
    }
}
```


#套路总结
---
- 我们从最暴力的O(n^2)看出来,两个interval相互比较能不能merge,想到能否只比较一边,从而想到排序。
- 当输入杂乱无章的时候可以考虑排序,固定一端检查另一端。
- 空间复杂度???
  - 其实我的理解是作为输出的space不计入复杂度,那么就是O(1),但是这个res确实是extra的,由于输入是List,那么我们想要在它本身里面去merge后删除一个interval其实代价也是O(n),那么对List做“inplace”操作反而效率不高,所以就直接另外new了一个List,这点可以跟面试官讨论。

LeetCode 186 Reverse Words in a String II

#**LeetCode186**
---
https://leetcode.com/problems/reverse-words-in-a-string-ii

Yifeng Zeng

#题目描述
---
Reverse Words in a String II
![](186.png)

#思路报告
---

最开始我是做的Lintcode的53题http://www.lintcode.com/en/problem/reverse-words-in-a-string/
输入输出都是String而不是char[],当时的思路是用String[] strs = s.split(" ");把输入String分成多个word。因为String在Java里面本来就是immutable的,所以这需要extra O(n)的space,然后输出也是String,所以可以直接用一个StringBuilder把Sting[] strs,从后往前拼接起来中间加空格即可,然后返回StringBuilder.toString()。所以time O(n),space O(n)。

代码如下:
```java

public String reverseWords(String str) {
        char[] s str.toCharArray();


        if (s == null || s.length() <= 1) {
            return s;
        }

        String[] strs = s.split(" ");
        StringBuilder sb = new StringBuilder();
        for (int i = strs.length - 1; i >= 0; i--) {
            sb.append(strs[i]);
            if (i != 0) {
                sb.append(" ");
            }
        }

        return sb.toString();
    }
```
LC186是输入char[] s返回为void,所以可以inplace的做space O(1)。由于做了上面lintcode的题我第一反应还是把char[]变成String然后根据上面的步骤得到return的String再String.toCharArray(),但是这样做明显复杂了。时间上都是O(n),且要遍历整个char[],所以没法优化了,所有只有优化空间想办法做O(1) space。每个word的长度显然不可能一样,那么左边一个word直接跟右边一个word交换明显太复杂不合适。那么先想到先整体reverse,这样的话每个word的位置已经正确,但是word本身就反过来了,那么再扫一遍把每一个word reverse一遍就可以了。怎么判断每一个word呢?那肯定需要两个指针,i指向word第一个char,j指向word最后一个char,那么j指向一个空格的时候j-1就指向了当前word的最后一个char,再把这个word reverse就好,那么最后一个word后面没有空格,所以扫面完后最后的i,j-1还需要再reverse一下。

代码如下

```java
public String reverseWords(String str) {
        char[] s = str.toCharArray();

        if (s == null || s.length <= 1) {
            return new String(s);
        }

        reverse(s, 0, s.length - 1);
        int i = 0;
        int j = 0;
        while (j < s.length) {
            if (s[j] == ' ') {
                reverse(s, i, j-1);
                i = j+1;
            }
            j++;
        }
        reverse(s, i, j-1);

        return new String(s);
    }

    private void reverse(char[] s, int i, int j) {
        while (i < j) {
            char t = s[i];
            s[i] = s[j];
            s[j] = t;
            i++;
            j--;
        }
    }
```

#套路总结
---
- 程序的模块化很重要,单独把reverse函数提出来就不用在主函数里面重复写多次了。
- 当时间复杂度不再能够被优化的时候,保持相同时间复杂度的情况下可以考虑优化空间。当然,经常也有通过空间换取时间的情况。

#Follow Up
---
- 有leading trailing space, 或者每个word之间不止一个space怎么处理。
  - 我觉得应该跟面试官讨论这种情况,看他想要怎么处理,是我的话我应该会说,ok, let's remove the leading trailing spaces for now,先不考虑它,word之间的spaces的话我reverse过来可不可以只留一个space,那么这样的话我就可以用我的第一种方法解了。

LeetCode 143 Reorder List

#**LeetCode 143**
---
https://leetcode.com/problems/reorder-list/description/

Yifeng Zeng

#题目描述
---
Reorder List

#思路报告
---

我们假定要reorder的list是dummy->1->2->3->4->5->...->n-1->n->Null
最primitive的想法是:
1. 先遍历一边list得到有n个点,先把1拿出来,并且把2记录下来,再从2找到n, 把n放到1后面,得到dummy->1->n->Null
2. 把2拿出来,并把3记录下来,再次3找到n-1,把他们连起来得到dummy->1->n->2->n-1->Null。
3. 重复上述步骤直到中点

这个时间复杂度应该是O(n^2)。那么我们怎么优化呢。

首先,我们找n, n-1, n-2...每一次都是遍历list,所以是O(n^2),那么如果我们有一个list是n->n-1->n-2->...那么我们就可以很方便的找到下一个candidate,所以我们想到了reverse linked list。而我们只需要翻转后半部的linked list,所以我们需要找到中点。找中点的操作我使用最常见的快慢指针,这里我就不介绍了。

代码如下:
```java
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void reorderList(ListNode head) {
        if (head == null) {
            return;
        }

        // find mid
        ListNode mid = findMid(head);
        // System.out.println(mid.val);

        // reverse
        ListNode tail = reverseList(mid.next);
        // tail will be the start of the second half
        mid.next = null; // actuall we don't need this
        // tail is now the start of the reversed second half
        // print(head);
        // print(tail);

        // now merge two list head & tail
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        while (head != null && tail != null) {
            cur.next = head;
            head = head.next;
            cur = cur.next;
            cur.next = tail;
            tail = tail.next;
            cur = cur.next;
        }
        cur.next = head;

        // return dummy.next;
    }

    private ListNode findMid(ListNode head) {
        ListNode slow = head;
        ListNode fast = head.next;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }

    private ListNode reverseList(ListNode head) {
        ListNode prev = null;
        while (head != null) {
            ListNode next = head.next;
            head.next = prev;
            prev = head;
            head = next;
        }
        return prev;
    }

    private void print(ListNode head) {
        while (head != null) {
            System.out.print(head.val + " ");
            head = head.next;
        }
        System.out.println();
    }
}
```



#套路总结
---
- 程序的模块化很重要,单独把findMid和reverseList函数提出来这样主函数会看起来比较清晰。
- 当找n,n-1,n-2...的时候前面的遍历都是重复的,所以想到反过来能不能行,所以想到了reverse后面一半。

MarkDown demo


>reference: http://www.cnblogs.com/fanzhidongyzby/p/6637084.html
https://zh.wikipedia.org/wiki/Markdown

---------------------------------------

1. 安装Atom

下载安装Atom:https://atom.io/

---

2. 增强预览(markdown-preview-plus)

支持预览实时渲染。(Ctrl + Shift + M)

支持Latex公式。(Ctrl + Shift + X)

\[
e ^ {i\pi} + 1 = 0
\]

e<sup>2</sup>

x<sub>0</sub>

~~Strikethrough~~

(C)Copyright

--

(R)

(TM)

(P)

+-

' '

'' ''

---

3. 同步滚动(markdown-scroll-sync) (好象有问题)

#一级标题

- 一
- 二
  - 2.1
  - 2.2
    - 2.2.1
    - 2.2.2
      - 2.2.2.1
      - 2.2.2.2
- 三



##二级标题 水平分割线

* * *
***
*****
- - -
---------------------------------------
---

###三级标题 强调

*强调(斜体)*
_强调(斜体)_

**加重强调**

又或者以制表符或至少四个空格缩进的行,例如:

    第一行代码
    第二行代码
    第三行代码

####四级标题 引用

> 这一整段的内容都会作为一个HTML的引用元素。
引用元素是会自动优化排版的(reflowable,可回流)。
你可以任意地将引用的内容包含进来,然后所有这些都会
被解析成为单独一个引用元素。

> 这是一个引用。这是第一行
这是第二行。
>> 这是一个嵌套的引用。这是第一行。
这是第二行
>
> 外层引用的第三行。前面需要一个视觉上的空行表示内层嵌套的结束,空行前面的>可以有可以没有。

---

4. 代码增强(language-markdown)
```Java
public String reverseWords(String str) {
        char[] s str.toCharArray();


        if (s == null || s.length() <= 1) {
            return s;
        }

        String[] strs = s.split(" ");
        StringBuilder sb = new StringBuilder();
        for (int i = strs.length - 1; i >= 0; i--) {
            sb.append(strs[i]);
            if (i != 0) {
                sb.append(" ");
            }
        }

        return sb.toString();
    }
```

---

5. 图片粘贴(markdown-image-paste)

截图到剪切板,Ctrl + V就可以直接贴
![](186.png)

---

6. 表格编辑(markdown-table-editor)

| Name   | Age | Weight |
| ------ | --- | ------ |
| Yifeng | 30  | 100    |
|        |     |        |




Tuesday, January 16, 2018

Java中如何遍历Map对象的4种方法.

“Java中如何遍历Map对象的4种方法.” Java中如何遍历Map对象的4种方法 - CSDN博客, blog.csdn.net/tjcyjd/article/details/11111401.

Thursday, November 9, 2017

What are carriage return, linefeed, and form feed?

https://stackoverflow.com/questions/3091524/what-are-carriage-return-linefeed-and-form-feed

“What Are Carriage Return, Linefeed, and Form Feed?” Newline - What Are Carriage Return, Linefeed, and Form Feed? - Stack Overflow, stackoverflow.com/questions/3091524/what-are-carriage-return-linefeed-and-form-feed.

Friday, June 30, 2017

Wednesday, June 14, 2017

Java - why doesn't ArrayList as key in HashMap work?

https://stackoverflow.com/questions/35560067/why-doesnt-arraylist-as-key-in-hashmap-work

“Why Doesn't ArrayList as Key in HashMap Work?” Java - Why Doesn't ArrayList as Key in HashMap Work? - Stack Overflow, stackoverflow.com/questions/35560067/why-doesnt-arraylist-as-key-in-hashmap-work. Accessed 14 June 2017.

Saturday, April 8, 2017

Does Java pass by reference or pass by value?

http://www.javaworld.com/article/2077424/learn-java/does-java-pass-by-reference-or-pass-by-value.html

Sintes, Tony. “Does Java Pass by Reference or Pass by Value?” JavaWorld, JavaWorld, 26 May 2000, www.javaworld.com/article/2077424/learn-java/does-java-pass-by-reference-or-pass-by-value.html. Accessed 8 Apr. 2017.