Saturday, September 30, 2017

217. Contains Duplicate

Version #2 Sort
Version #1 HashSet

68.38 %
class Solution {
    public boolean containsDuplicate(int[] nums) {
        if (nums == null || nums.length <= 1) return false;
        Set<Integer> visited = new HashSet<>();
        for (int num : nums) {
            if (!visited.add(num)) return true;
        }
        return false;
    }
}

Wednesday, September 27, 2017

19. Remove Nth Node From End of List

三刷 06/2022
Version #1 Two Passes - get length
Time O(N)
Space O(1)
Runtime: 0 ms, faster than 100.00% of Java online submissions for Remove Nth Node From End of List.
Memory Usage: 43.2 MB, less than 5.08% of Java online submissions for Remove Nth Node From End of List.
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode curr = head;
        int cnt = 0;
        // c
        // 1
        while (curr != null) {
            cnt++;
            curr = curr.next;
        }
        // m is zero based index of the node to be deleted
        int m = cnt - n;
        if (m == 0) {
            return head.next;
        }
        curr = head;
        // c
        // 1 2 3 - m = 1
        while (m-- > 1) {
            curr = curr.next;
        }
        curr.next = curr.next.next;
        return head;
    }
}
Version #2 One Pass
Time O(N)
Space O(1)

Runtime: 1 ms, faster than 65.32% of Java online submissions for Remove Nth Node From End of List.
Memory Usage: 42.8 MB, less than 17.25% of Java online submissions for Remove Nth Node From End of List.

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // s
        //     f
        // 1 2 3 4 5
        // s
        // f
        // 1
        ListNode slow = head, fast = head;
        while (n-- > 0 && fast != null) {
            fast = fast.next;
        }
        if (fast == null) {
            return head.next;
        }
        while (fast.next != null) {
            slow = slow.next;
            fast = fast.next;
        }
        slow.next = slow.next.next;
        return head;
    }
}


Version #2 One pass
Two pointers
Find a node which is n nodes away from head -> curr
Define prev as the previous node of head
let curr go forward until it reaches tail, and prev also walk in the same pace
When curr reaches null, prev.next is n nodes away from curr -> we should remove prev.next
-> prev.next = prev.next.next

二刷
50.57 %
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //prev           p        c   
        //dummy -> 1->2->3->4->5->null
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode prev = dummy;
        ListNode curr = head;
        while (n > 0) {
            curr = curr.next;
            n--;
        }
        while (curr != null) {
            prev = prev.next;
            curr = curr.next;
        }
        prev.next = prev.next.next;
        return dummy.next;
    }
}


一刷
67.80 %
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null || n == 0) return head;
        // n = 1
        //sf
        // 1-> 2 -> null
        ListNode fast = head;
        ListNode slow = head;
        while (n-- > 0 && fast != null) {
            fast = fast.next;
        }
        if (fast == null) return head.next;
        while (fast.next != null) {
            slow = slow.next;
            fast = fast.next;
        }
        slow.next = slow.next.next;
        return head;
    }
}



Version #1 Two pass
二刷
 99.83 %
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        int len = 0;
        ListNode curr = head;
        while (curr != null) {
            len++;
            curr = curr.next;
        }
        // len = 5, target = 0
        int target = len - n;
        //       p
        // 1->2->3->4->5
        ListNode prev = dummy;
        while (target > 0) {
            prev = prev.next;
            target--;
        }
        prev.next = prev.next == null ? null : prev.next.next;
        return dummy.next;
    }
}


一刷
getLength
14.97 %
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null || n == 0) return head;
        int len = getLength(head);
        // e.g. len = 5, n = 2 delete index (5 - 2) = 3
        // i 0  1  2  3
        //   1->2->null
        ListNode curr = head;
        if (n == len) return head.next;
     
        for (int i = 0; i < len - n - 1; i++) {
            curr = curr.next;
        }
     
        curr.next = curr.next.next;
        return head;
    }
    private int getLength(ListNode head) {
        int len = 0;
        while (head != null) {
            len++;
            head = head.next;
        }
        return len;
    }
}

Friday, September 22, 2017

218. The Skyline Problem

[DONE] Write a int[2] version
四刷
38.16 %
class Solution {
    public List<int[]> getSkyline(int[][] buildings) {
        // check if the highest hight has changed or not
        // int[] 0-represents the x, 0-represents height, minus if it is the end
        List<int[]> heights = new ArrayList<>();
        for (int[] building : buildings) {
            // building[0] -> start
            // building[1] -> end
            // building[2] -> height
            heights.add(new int[]{building[0], building[2]});
            heights.add(new int[]{building[1], -building[2]});
        }
        // compare by x
        // if 1 end and 1 start, start should come before end
        // if both start, heigher one should come first
        // if both end, lower one should come first
        Collections.sort(heights, (a, b) -> {
            if (a[0] != b[0]) {
                return a[0] - b[0];
            }
            return b[1] - a[1];
        });
        // all the points that are under consideration
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
        maxHeap.offer(0);
        List<int[]> result = new ArrayList<>();
        int currHeight = 0;
        for (int[] height : heights) {
            if (height[1] > 0) {
                maxHeap.offer(height[1]);
            } else {
                maxHeap.remove(-height[1]);
            }
            if (maxHeap.peek() != currHeight) {
                currHeight = maxHeap.peek();
                result.add(new int[]{height[0], currHeight});
            }
        }
        return result;
    }
}


[3rd TRY]
1 bug -> should have checked if pq is empty before do pq.peek()

51.67 %
class Solution {
    class Point {
int x;
int height;
int isEnd; // 0 for start, 1 for end
public Point(int x, int height, int isEnd) {
this.x = x;
this.height = height;
this.isEnd = isEnd;
}
}
    public List<int[]> getSkyline(int[][] buildings) {
// we keep a list of heights -> if the highest point changes, then it should be added to skyline
// sort by their x positions, we need to know either it is a start point or a end point
// 4 kinds of ties
// if a ends and b starts, a < b, then we want to add b first and then remove a -> start 0, end 1
// if a ends and b starts, a > b, same
// if a,b ends at the same time, then we want to remove the lower one first
// if a,b stars at the same time, then we want to add the higher one first
List<Point> list = new ArrayList<>();
for (int[] building : buildings) {
list.add(new Point(building[0], building[2], 0));
list.add(new Point(building[1], building[2], 1));
}
Collections.sort(list, (a, b) -> {
if (a.x != b.x) {
return a.x - b.x;
}
if (a.isEnd != b.isEnd) {
return a.isEnd - b.isEnd; // Always return the start one first
} else if (a.isEnd == 0) {
return b.height - a.height;
} else {
return a.height - b.height;
}
});
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(16, Collections.reverseOrder());
int prevHeight = 0;
List<int[]> result = new ArrayList<>();
for (Point curr : list) {
if (curr.isEnd == 0) { // isStart
maxHeap.add(curr.height);
} else {
maxHeap.remove(curr.height);
}
int currHeight = maxHeap.isEmpty() ? 0 : maxHeap.peek();
if (currHeight != prevHeight) {
prevHeight = currHeight;
result.add(new int[]{curr.x, currHeight});
}
}
return result;
}
}



二刷
Time O(n^2) -> linear time to remove
Space O(n)
class Solution {
    // int[0] -> x, int[1] -> height, int[2] -> 0 start, 1 end
    public List<int[]> getSkyline(int[][] buildings) {
        List<int[]> result = new ArrayList<>();
        if (buildings == null || buildings.length == 0) {
            return result;
        }
        // buildings[i][0] -> start, buildings[i][1] -> end, buildings[i][2] -> height
        List<int[]> list = new ArrayList<>();
        for (int[] building : buildings) {
            list.add(new int[]{building[0], building[2], 0});
            list.add(new int[]{building[1], building[2], 1});
        }
        Collections.sort(list, (a, b) -> {
            if (a[0] != b[0]) {
                return a[0] - b[0];
            } else if (a[2] != b[2]) {
                // start before end
                return a[2] - b[2];
            } else if (a[2] == 0) {
                // Two start, add the higher one first
                return b[1] - a[1];
            } else {
                // Two end, remove the lower one first
                return a[1] - b[1];
            }
        });
        PriorityQueue<Integer> pq = new PriorityQueue<>(10, Collections.reverseOrder());
        int currHeight = 0;
        int[] curr = null;
        for (int i = 0; i < list.size(); i++) {
            curr = list.get(i);
            if (curr[2] == 0) {
                pq.add(curr[1]);
            } else {
                pq.remove(curr[1]);
            }
            if (pq.isEmpty()) {
                result.add(new int[]{curr[0], 0});
                currHeight = 0;
            } else if (currHeight != pq.peek()){
                result.add(new int[]{curr[0], pq.peek()});
                currHeight = pq.peek();
            }
        }
        return result;
    }
}





一刷

Input:[[0,2,3],[2,5,3]]
Output:[[0,3],[2,3],[5,0]]
Expected:[[0,3],[5,0]]
有四种breaking tie的情况,决定了sort的顺序
上面的一个bug要注意如果second largest和之前pop出去的一样高,就不往结果里面加

还有一个是PriorityQueue remove(Object)
是remove single one

 59.53 %

class Solution {
    class Tuple {
        int pos;
        int height;
        int isEnd; // 0 -> isStart, 1 -> isEnd
        public Tuple(int pos, int height, int isEnd) {
            this.pos = pos;
            this.height = height;
            this.isEnd = isEnd;
        }
    }
    public List<int[]> getSkyline(int[][] buildings) {
        List<int[]> result = new ArrayList<>();
        if (buildings == null || buildings.length == 0) return result;
        List<Tuple> tuples = new ArrayList<>();
        for (int[] building : buildings) {
            //  0   1   2
            // [Li, Ri, Hi]
            tuples.add(new Tuple(building[0], building[2], 0));
            tuples.add(new Tuple(building[1], building[2], 1));
        }
        // maxHeap
        PriorityQueue<Integer> pq = new PriorityQueue<>(10, Collections.reverseOrder());
   
        Collections.sort(tuples, new Comparator<Tuple>() {
            @Override
            public int compare(Tuple t1, Tuple t2) {
                if (t1.pos != t2.pos) {
                    return t1.pos - t2.pos;
                } else if (t1.isEnd != t2.isEnd) {
                    // start(0) befor end(1)
                    return t1.isEnd - t2.isEnd;
                } else if (t1.isEnd == 0) {
                    // if both start, higher before lower
                    return t2.height - t1.height;
                } else {
                    // if both end, lower before higher
                    return t1.height - t2.height;
                }
            }
        });
        // output [x1,y1] -> [pos, height]
        for (int i = 0; i < tuples.size(); i++) {
            Tuple curr = tuples.get(i);
            // start -> add
            if (curr.isEnd == 0) {
           
                if (pq.isEmpty() || curr.height > pq.peek()) {
                    result.add(new int[]{curr.pos, curr.height});
                }
                pq.add(curr.height);
            } else { // end -> delete
                if (pq.peek() == curr.height) {
                    pq.poll();
                    if (pq.isEmpty()) {
                        result.add(new int[]{curr.pos, 0});
                    } else if (pq.peek() != curr.height){
                        result.add(new int[]{curr.pos, pq.peek()});
                    }
                } else {
                    pq.remove(new Integer(curr.height));
                }
            }
        }
        return result;
    }
}

Wednesday, September 20, 2017

393. UTF-8 Validation


报错的算是一个edge case
如果只有1byte,应该是0 开头
也就是说不存在只有一个1开头的meta data

Input:[145]
Output:true
Expected:false
10010001

68.61 %

class Solution {
    public boolean validUtf8(int[] data) {
        if (data == null || data.length == 0) return false;
        return helper(data, 0, 0);
    }
    private boolean helper(int[] data, int index, int toMatch) {
        if (index == data.length) return toMatch == 0;
        int curr = data[index];
     
        if (toMatch != 0) {
            if (curr >> 6 != 0b10) return false;
            else return helper(data, index + 1, toMatch - 1);
        }
        // get the count of 1s
        int count = 0;
        int bit = 7;
        while ((curr & (1 << bit--)) != 0) {
            count++;
        }
        // can't be 1 since 1 byte is a special case
        // can't be more than 4 bytes
        if (count == 1 || count > 4) return false;
        count = count == 0 ? 0 : count - 1;
        return helper(data, index + 1, count);
    }
}

Tuesday, September 19, 2017

219. Contains Duplicate II

二刷
Versuib #2 Sliding Window
14.63 %
class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        if (nums == null) {
            return false;
        }
        // sliding window of size k
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            if (set.size() > k) {
                set.remove(nums[i - k - 1]);
            }
            if (set.contains(nums[i])) {
                return true;
            }
            set.add(nums[i]);
        }
        return false;
    }
}

Version #1 第一反应还是写了hashmap
Seems like this problem is actually a sliding window problem
81.40 %
class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        // key-> num, value -> index
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            Integer index = map.get(nums[i]);
            if (index != null && i - index <= k) {
                return true;
            }
            map.put(nums[i], i);
        }
        return false;
    }
}


一刷
Version #2 HashSet(Better)
82.57 %
class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        if (nums == null || nums.length <= 1) return false;
        // set of numbers in the sliding window
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            // i - j <= k ->  j >= i - k
            if (i - k > 0) {
                set.remove(nums[i - k - 1]);
            }
            if (!set.add(nums[i])) return true;
        }
        return false;
    }
}

Version #1 HashMap
看了答案发现自己这么写很烂
这个题有点像sliding window
只要用set看window里面有没有重复值就可以了

9.84 %
class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        if (nums == null || nums.length <= 1) return false;
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int prev = map.getOrDefault(nums[i], -1);
            if (prev != -1 && i - prev <= k) {
                return true;
            } else {
                map.put(nums[i], i);
            }
        }
        return false;
    }
}

253. Meeting Rooms II

三刷
Version #3 Sort start & end at the same time

3.68 %
class Solution {
    public int minMeetingRooms(Interval[] intervals) {
        if (intervals == null || intervals.length == 0) return 0;
        List<int[]> list = new ArrayList<>();
        for (Interval interval : intervals) {
            list.add(new int[]{interval.start, 1});
            list.add(new int[]{interval.end, -1});
        }
        Collections.sort(list, (a, b) -> {
            if (a[0] == b[0]) return a[1] - b[1]; // end happens before start
            return a[0] - b[0];
        });
        int count = 0;
        int result = 0;
        for (int i = 0; i < list.size(); i++) {
            count += list.get(i)[1];
            result = Math.max(result, count);
        }
        return result;
    }
}


Version #2
sort start & end separately
用count表示现在有的meeting rooms的数量
如果有meeting结束 可以把后面的放进vacant的room
如果没有结束的meeting 就需要增加rooms的数量
81.05 %
class Solution {
    public int minMeetingRooms(Interval[] intervals) {
        if (intervals == null || intervals.length == 0) return 0;
        int length = intervals.length;
        int[] starts = new int[length];
        int[] ends = new int[length];
        for (int i  = 0; i < length; i++) {
            starts[i] = intervals[i].start;
            ends[i] = intervals[i].end;
        }
        Arrays.sort(starts);
        Arrays.sort(ends);
        int count = 0;
        int pEnd = 0;
        for (int pStart = 0; pStart < length; pStart++) {
            if (starts[pStart] < ends[pEnd]) {
                count++;
            } else {
                pEnd++;
            }
        }
        return count;
    }
}

Version #1 Naive Sort Intervals Version
重点是breaking tie
看到discuss里面还有用heap和分别sort start&end的方法,懒得看了

49.06 %
class Solution {
    class Tuple implements Comparable<Tuple> {
        int time;
        int isStart; //start -> 1, end -> 0
        public Tuple(int time, int isStart) {
            this.time = time;
            this.isStart = isStart;
        }
        @Override
        public int compareTo(Tuple that) {
            if (this.time != that.time) {
                return this.time - that.time;
            } else {
                return this.isStart - that.isStart;
            }
        }
    }
    public int minMeetingRooms(Interval[] intervals) {
        if (intervals == null || intervals.length == 0) return 0;
        List<Tuple> times = new ArrayList<>();
        for (Interval i : intervals) {
            times.add(new Tuple(i.start, 1));
            times.add(new Tuple(i.end, 0));
        }
        Collections.sort(times);
        int max = 0;
        int count = 0;
        for (Tuple tuple : times) {
            if (tuple.isStart == 1) {
                count++;
                max = Math.max(count, max);
            } else {
                count--;
            }
        }
        return max;
    }
}

416. Partition Equal Subset Sum

二刷 07/2022

Version #1 0/1 Knapsack
Time O(N * Sum)
Space O(N * Sum)
Runtime: 26 ms, faster than 91.77% of Java online submissions for Partition Equal Subset Sum.
Memory Usage: 43.5 MB, less than 75.86% of Java online submissions for Partition Equal Subset Sum.

class Solution {
    public boolean canPartition(int[] nums) {
        int target = 0;
        for (int num : nums) {
            target += num;
        }
        if (target % 2 != 0) {
            return false;
        }
        target /= 2;
        // dp[i][s] - [0, i) numbers can add up to s
        boolean[][] dp = new boolean[nums.length + 1][target + 1];
        dp[0][0] = true;
        for (int i = 1; i <= nums.length; i++) {
            for (int j = target; j >= 0; j--) {
                if (dp[i - 1][j] || (j >= nums[i - 1] && dp[i - 1][j - nums[i - 1]])) {
                    dp[i][j] = true;
                }
            }
            if (dp[i][target]) {
                return true;
            }
        }
        return dp[nums.length][target];
    }
}


Version #2 HashSet
Time O(N * Sum of all numbers)
Space O(Sum of all numbers)

Runtime: 410 ms, faster than 5.82% of Java online submissions for Partition Equal Subset Sum.
Memory Usage: 117.8 MB, less than 6.46% of Java online submissions for Partition Equal Subset Sum.

class Solution {
    public boolean canPartition(int[] nums) {
        int target = 0;
        for (int num : nums) {
            target += num;
        }
        if (target % 2 != 0) {
            return false;
        }
        target /= 2;
        Set<Integer> visited = new HashSet<>();
        visited.add(0);
        for (int num : nums) {
            Set<Integer> newSum = new HashSet<>();
            for (int prev : visited) {
                if (prev + num == target) {
                    return true;
                }
                newSum.add(prev + num);
            }
            visited.addAll(newSum);
        }
        return false;
    }
}


一刷 06/2022
Version #1 0/1 Knapsack DP
It could be optimized to 1d DP

Time O(N*Sum)
Space O(N*Sum)
Runtime: 51 ms, faster than 61.41% of Java online submissions for Partition Equal Subset Sum.
Memory Usage: 54.3 MB, less than 44.88% of Java online submissions for Partition Equal Subset Sum.

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if (sum % 2 != 0) {
            return false;
        }
        sum /= 2;
        // System.out.printf("sum=%d\n", sum);
        // The [0, i) numbers can sum up to j
        boolean[][] dp = new boolean[nums.length + 1][sum + 1];
        // The first 0 number can sum up to 0
        dp[0][0] = true;
        for (int i = 1; i <= nums.length; i++) {
            // the nums[i - 1] item
            int num = nums[i - 1];
            for (int j = 0; j < sum + 1; j++) {
                if (num <= j) {
                    dp[i][j] = dp[i - 1][j] || dp[i - 1][j - num];
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
            if (dp[i][sum]) {
                return true;
            }
        }
        return dp[nums.length][sum];
    }
}

297. Serialize and Deserialize Binary Tree

参考 449. Serialize and Deserialize BST
Version #5 Byte Manipulation
这个方法是把Integer直接变成string给改成byte 表示法,可以压缩space
String ->
-2^31 =  -2147483648 -> 11 chars
https://www.javamex.com/tutorials/memory/string_memory_usage.shtml
Byte -> 0xFFFFFFFF
4 bytes
No string-integer conversion needed

如果是 int -> byte[] -> char[] 的话,转换回来的时候
如果不
// return (int) ((data[0] & 0xff) << 24)
        //     | ((data[1] & 0xff) << 16)
        //     | ((data[2] & 0xff) << 8)
        //     | (data[3] & 0xff);
就会出错

然而如果直接 int -> char[]就不需要考虑这个问题,因为在int -> char[] 的时候已经
 (char)((x >> 24) & 0xff),
            (char)((x >> 16) & 0xff),
            (char)((x >> 8) & 0xff),
            (char)(x & 0xff)



99.15 %

public class Codec {
    private char NULL_VALUE = '0';
    private char NOT_NULL_VALUE = '1';
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        seHelper(root, sb);
        return sb.toString();
    }
 
    private void seHelper(TreeNode node, StringBuilder sb) {
        if (node == null) {
            sb.append(NULL_VALUE);
            return;
        }
        char[] array = int2Bytes(node.val);
        sb.append(NOT_NULL_VALUE).append(array[0]).append(array[1]).append(array[2]).append(array[3]);
        seHelper(node.left, sb);
        seHelper(node.right, sb);
    }
 
    private char[] int2Bytes(int x) {
        return new char[]{
            (char)((x >> 24) & 0xff),
            (char)((x >> 16) & 0xff),
            (char)((x >> 8) & 0xff),
            (char)(x & 0xff)
        };
    }

    // Decodes your encoded data to tree.
    private int index;
    public TreeNode deserialize(String data) {
        index = 0;
        return deHelper(data.toCharArray());
    }
 
    private TreeNode deHelper(char[] data) {
        if (data[index++] == NULL_VALUE) {
            return null;
        }
        TreeNode node = new TreeNode(bytes2Int(new char[]{
            data[index],
            data[index + 1],
            data[index + 2],
            data[index + 3]
        }));
        index += 4;
        node.left = deHelper(data);
        node.right = deHelper(data);
        return node;
    }
    private int bytes2Int(char[] data) {
        return (int) (data[0] << 24)
            | (data[1] << 16)
            | (data[2] << 8)
            | data[3];
    }
}



Version #3 Iteration with Stack
二刷
看一刷的不知道自己在写什么。。。为什么需要一个boolean来判断是不是left?
Stack 加的时候注意是先左后右
Stack deserialize的时候,都是向左走到底,然后向右跳一个
39.88 %
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        Deque<TreeNode> stack = new LinkedList<>();
        stack.addFirst(root);
        while (!stack.isEmpty()) {
            TreeNode curr = stack.removeFirst();
            if (curr == null) {
                sb.append("#,");
            } else {
                sb.append(curr.val + ",");
                stack.addFirst(curr.right);
                stack.addFirst(curr.left);
            }
        }
        System.out.println(sb.toString());
        return sb.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if (data == null || data.length() == 0) {
            return null;
        }
        String[] strs = data.split(",");
        Deque<TreeNode> stack = new LinkedList<>();
        int pointer = 0;
        if (strs.length == 0 || strs[pointer].equals("#")) {
            return null;
        }
        TreeNode root = new TreeNode(Integer.valueOf(strs[0]));
        TreeNode curr = root;
        stack.addFirst(root);
        pointer++;
        while (pointer < strs.length) {
            while (curr != null) {
                stack.addFirst(curr);
                curr.left = strs[pointer].equals("#") ? null : new TreeNode(Integer.valueOf(strs[pointer]));
                pointer++;
                curr = curr.left;
            }
            curr = stack.removeFirst();
            curr.right = strs[pointer].equals("#") ? null : new TreeNode(Integer.valueOf(strs[pointer]));
            pointer++;
            curr = curr.right;
        }
        return root;
    }
}

一刷
Iteration desirialization 好难啊,写了好久好久好久
stack里面放的是已经连完左节点但是等待右subtree的点
curr代表的是当下等待连左节点的点

如果遇到null
1st -> 证明当前curr的left subtree是null
          当前curr已经是Left most node
          开始往外pop
2nd -> 在pop round,pop出的点是waiting for its right subtree
           此时遇到null 证明当前点的right subtree是NULL
           直接继续pop

37.48 %
public class Codec {
    private static final String DIVIDER = "/";
    private static final String NULL = "null";
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) return null;
        StringBuilder sb = new StringBuilder();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curr = root;

        while (curr != null || !stack.isEmpty()) {
            if (curr != null) {
                sb.append(curr.val);
                sb.append(DIVIDER);
                stack.push(curr);
                curr = curr.left;
            } else {
                sb.append(NULL + DIVIDER);
                curr = stack.pop();
                curr = curr.right;
            }
   
        }
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if (data == null) return null;
        String[] strs = data.trim().split(DIVIDER);
        int index = 0;
        TreeNode root = new TreeNode(Integer.valueOf(strs[index++]));
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curr = root;
        stack.push(curr);
        int n = strs.length;
        // Nodes in stack -> waiting for their right subtree
        // curr -> waiting for its left subtree
        while (index < n) {
            while (index < n && !strs[index].equals(NULL)) {
                curr.left = new TreeNode(Integer.valueOf(strs[index++]));
                curr = curr.left;
                stack.push(curr);
            }
            // Top nodes left subtree is null, get the next candidate node
            while (index < n && strs[index].equals(NULL)) {
                curr = stack.pop();
                index++;
            }
            // strs[index] is not NULL
            if (index < n) {
                curr.right = new TreeNode(Integer.valueOf(strs[index++]));
                curr = curr.right;
                stack.push(curr);
            }
        }
        return root;
    }
}


Version #4 Recursion DFS
Pre-Order Traversal
注意pointer是一个global变量,每一次recursion的当前层负责给pointer + 1
二刷
94.28 %
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        seHelper(root, sb);
        return sb.toString();
    }
    private void seHelper(TreeNode node, StringBuilder sb) {
        if (node == null) {
            sb.append("#,");
            return;
        }
        sb.append(node.val + ",");
        seHelper(node.left, sb);
        seHelper(node.right, sb);
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if (data == null || data.length() == 0) {
            return null;
        }
        String[] strs = data.split(",");
        int[] pointer = new int[]{0};
        return deHelper(strs, pointer);
    }
    private TreeNode deHelper(String[] strs, int[] pointer) {
        if (strs[pointer[0]].equals("#")) {
            pointer[0]++;
            return null;
        }
        TreeNode node = new TreeNode(Integer.valueOf(strs[pointer[0]]));
        pointer[0]++;
        node.left = deHelper(strs, pointer);
        node.right = deHelper(strs, pointer);
        return node;
    }
}


Version #1 jiuzhang Version BFS with Queue
二刷
49.87 %
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        Queue<TreeNode> que = new LinkedList<>();
        if (root == null) {
            return null;
        }
        que.offer(root);
        while (!que.isEmpty()) {
            TreeNode curr = que.poll();
            if (curr == null) {
                sb.append("#,");
            } else {
                sb.append(curr.val + ",");
                que.offer(curr.left);
                que.offer(curr.right);
            }
        }
        return sb.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if (data == null || data.length() == 0) {
            return null;
        }
        String[] strs = data.split(",");
        Queue<TreeNode> que = new LinkedList<>();
        if (strs.length == 0) {
            return null;
        }
        int pointer = 0;
        TreeNode root = new TreeNode(Integer.valueOf(strs[pointer++]));
        que.offer(root);
        while (!que.isEmpty()) {
            TreeNode curr = que.poll();
            TreeNode left = null;
            if (!strs[pointer].equals("#")) {
                left = new TreeNode(Integer.valueOf(strs[pointer]));
                que.offer(left);
            }
            pointer++;
            curr.left = left;
       
            TreeNode right = null;
            if (!strs[pointer].equals("#")) {
                right = new TreeNode(Integer.valueOf(strs[pointer]));     
                que.offer(right);
            }
            pointer++;
            curr.right = right;
        }
        return root;
    }
}
一刷
49.35 %
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) return "{}";
        ArrayList<TreeNode> que = new ArrayList<>();
        que.add(root);
        TreeNode curr = null;
        for (int i = 0; i < que.size(); i++) {
            curr = que.get(i);
            if (curr == null) continue;
            que.add(curr.left);
            que.add(curr.right);
        }
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        curr = que.get(0);
        int index = 1;
        sb.append(String.valueOf(curr.val));
        while (index < que.size()) {
            curr = que.get(index);
            index++;
            sb.append(",");
            if (curr == null) sb.append("#");
            else sb.append(String.valueOf(curr.val));
        }
        sb.append("}");
        return sb.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if (data.equals("{}")) {
            return null;
        }
        String[] vals = data.substring(1, data.length() - 1).split(",");
        ArrayList<TreeNode> queue = new ArrayList<TreeNode>();
        TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
        queue.add(root);
        int index = 0;
        boolean isLeftChild = true;
        for (int i = 1; i < vals.length; i++) {
            if (!vals[i].equals("#")) {
                TreeNode node = new TreeNode(Integer.parseInt(vals[i]));
                if (isLeftChild) {
                    queue.get(index).left = node;
                } else {
                    queue.get(index).right = node;
                }
                queue.add(node);
            }
            if (!isLeftChild) {
                index++;
            }
            isLeftChild = !isLeftChild;
        }
        return root;

    }
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));

Version #2

 57.60 %
自己改进了一下感觉比上个方法简洁一点 就是传统地用queue
上个方法里面用ArrayList作为Queue然后用get(index) 来代替queue.poll()感觉也挺有意思的
注意!string == "#"是不对的 必须string.equals("#");
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) return "";
        StringBuilder sb = new StringBuilder();
        Queue<TreeNode> que = new LinkedList<>();
        que.add(root);
        TreeNode curr = null;
        while (!que.isEmpty()) {
            curr = que.poll();
            if (curr == null) {
                sb.append("#,");
                continue;
            } else {
                sb.append(String.valueOf(curr.val));
                sb.append(",");
            }
            que.add(curr.left);
            que.add(curr.right);
        }
        char c = sb.charAt(sb.length() - 1);
        do {
            sb.deleteCharAt(sb.length() - 1);
            c = sb.charAt(sb.length() - 1);
        } while (c == '#' || c == ',');

        //System.out.println(sb.toString());
        return sb.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if (data == "") return null;
        String[] vals = data.split(",");
        Queue<TreeNode> que = new LinkedList<>();
        TreeNode root = new TreeNode(Integer.valueOf(vals[0]));
        que.add(root);
        TreeNode curr = null;
        boolean isLeft = true;
        for (int index = 1; index < vals.length; index++) {
            if (vals[index].equals("#")) {
                curr = null;
            } else {
                curr = new TreeNode(Integer.valueOf(vals[index]));
                que.add(curr);
            }
            if (isLeft) {
                que.peek().left = curr;
            } else {
                que.poll().right = curr;
            }
            isLeft = !isLeft;
        }
        return root;
    }
}

373. Find K Pairs with Smallest Sums

Version #1 MinHeap with Lambda

41.23 %
class Solution {
    public List<int[]> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        List<int[]> result = new ArrayList<>();
        if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) return result;
        // minHeap -> always poll out the minimum sum and add its adjacent sums
        PriorityQueue<int[]> minHeap = new PriorityQueue<>(10, (pairA, pairB) ->
                                                           (nums1[pairA[0]] + nums2[pairA[1]]) - (nums1[pairB[0]] + nums2[pairB[1]]));
        minHeap.offer(new int[]{0, 0});
        while (k-- > 0 && !minHeap.isEmpty()) {
            int[] curr = minHeap.poll();
            int i1 = curr[0];
            int i2 = curr[1];
            result.add(new int[]{nums1[i1], nums2[i2]});
            if (i1 == 0 && (i2 + 1 < nums2.length)) minHeap.offer(new int[]{i1, i2 + 1});
            if (i1 + 1 < nums1.length) minHeap.offer(new int[]{i1 + 1, i2});
        }
     
        return result;
    }
}

Version #2 Self-defined  class -> Tuple with is own compareTo method
LC上看到的,拿过来做reference
如果lambda写不好可以参考这个方法
92.17 %

"public class Solution {
public List<int[]> kSmallestPairs(int[] nums1, int[] nums2, int k) { PriorityQueue<Tuple> pq = new PriorityQueue<Tuple>(); int m = nums1.length, n = nums2.length; List<int[]> res = new ArrayList<int[]>(); if(nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0 || k <= 0) return res; for(int j = 0; j <= n-1; j++) pq.offer(new Tuple(0, j, nums1[0]+nums2[j])); for(int i = 0; i < Math.min(k, m *n); i++) { Tuple t = pq.poll(); res.add(new int[]{nums1[t.x], nums2[t.y]}); if(t.x == m - 1) continue; pq.offer(new Tuple (t.x + 1, t.y, nums1[t.x + 1] + nums2[t.y])); } return res; } } class Tuple implements Comparable<Tuple> { int x, y, val; public Tuple (int x, int y, int val) { this.x = x; this.y = y; this.val = val; } @Override public int compareTo (Tuple that) { return this.val - that.val; } }"