2015年4月30日星期四

Linked List Cycle II leetcode

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
题解:(转自http://www.cnblogs.com/springfor/p/3862125.html) 
这个连同I都是很经典的题啦,刷CC150时候就折磨了半天。
其实就推几个递推公式就好。。首先看图(图引用自CC150):
 
从链表起始处到环入口长度为:a,从环入口到Faster和Slower相遇点长度为:x,整个环长为:c。
明确了以上信息,就可以开始做运算了。。

 假设从开始到相遇,Slower走过的路程长为s,由于Faster的步速是Slower的2倍,那么Faster在这段时间走的路程长为2s。
 而对于Faster来说,他走的路程还等于之前绕整个环跑的n圈的路程nc,加上最后这一次遇见Slower的路程s。
 所以我们有:
                   2s = nc + s 
 对于Slower来说,他走的路程长度s还等于他从链表起始处到相遇点的距离,所以有:
                    s = a + x 
 通过以上两个式子代入化简有:
                    a + x = nc
                    a = nc - x
                    a = (n-1)c + c-x
                    a = kc + (c-x)
那么可以看出,c-x,就是从相遇点继续走回到环入口的距离。上面整个式子可以看出,如果此时有个pointer1从起始点出发并且同时还有个pointer2从相遇点出发继续往前走(都只迈一步),那么绕过k圈以后, pointer2会和pointer1在环入口相遇。这样,换入口就找到了。
时间复杂度 O(n)
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null){//必须包含head.next的判定
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast!= null && fast.next != null){//注意此处的判定
            fast = fast.next.next;
            slow = slow.next;
            if (slow == fast){
                break;
            }
        }
        if (fast != slow){
            return null;
        }
        fast = head;
        while (fast != slow){
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
        
    }
}

LinkedList总结

two pointer

dummynode

2015年4月29日星期三

Convert Sorted Array to Binary Search Tree leetcode

Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
选择中点构造根节点然后递归构造左子树和右子树
因为递归时候要记录一个起始位置一个终止位置, 所以构造一个helper函数
注意中点被构造成root 所以递归带入是mid-1 和mid+1 所以边界条件是start > end
时间复杂度还是一次树遍历O(n),空间复杂度是栈空间O(logn)加上结果的空间O(n),所以额外空间是O(logn),总体是O(n)。
/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode sortedArrayToBST(int[] num) {
        if (num == null || num.length == 0){
            return null;
        }
        return helper(num, 0, num.length - 1);
    }
    private TreeNode helper(int[] num, int start, int end){
        if (start > end){//因为是mid-1 和mid+1 所以到最后会出现start<end 而不是等于
            return null;
        }
        int mid = (start + end)/2;
        TreeNode node = new TreeNode(num[mid]);
        node.left = helper(num, start, mid-1);
        node.right = helper(num, mid + 1, end);
        return node;
    }
}

Copy List with Random Pointer leetcode

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
第一种方法:用hashmap
1. 把新链表和原链表按照key: value存入hashmap, 并给每个新链表附上next指针
2. 按顺序读取hashp存储的旧链表, 然后把random指针复制给新链表(必须放在hashmap读取是因为直接读取random指针就无法按顺序)
一共扫面了两次链表 时间复杂度O(n) 空间复杂度O(n)

public class Solution {
    public RandomListNode copyRandomList(RandomListNode head) {
        if (head == null){ 
            return null;
        }
        HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
        RandomListNode newhead = new RandomListNode(head.label);
        map.put(head, newhead);
        RandomListNode node = head.next;
        RandomListNode pre = newhead;
        while (node != null){
            RandomListNode tem = new RandomListNode(node.label);
            map.put(node, tem);
            pre.next = tem;
            pre = pre.next;
            node = node.next;
        }
        node = head;
        pre = newhead;
        while (node != null){
            pre.random = map.get(node.random);
            pre = pre.next;
            node = node.next;
        }
        return newhead;
        
    }
}


第二种方法:
深度拷贝一个链表

第一步:复制链表并插入原链表原链表(1->2->3->4)新链表(1->1'->2->2'->3->3'->4->4')
第二步: 改变新链表的random指针
第三步:分离连个链表
三次线性扫描,所以时间复杂度是O(n)。空间复杂度是O(1)。
public class Solution {
    public RandomListNode copyRandomList(RandomListNode head) {
        if (head == null) {
            return null;
        }
        RandomListNode node = head;
        while (node != null) {
            RandomListNode tem = new RandomListNode(node.label);
            tem.next = node.next;
            node.next = tem;
            node = node.next.next;
        }
        node = head;
        while (node != null) {
            if (node.random != null) {
                node.next.random = node.random.next;
            }
            node = node.next.next;
        }
        node = head;
        RandomListNode newhead = head.next;
        while(node != null){
            RandomListNode tem = node.next;
            node.next = tem.next;
            if (tem.next != null) {
                tem.next = tem.next.next;
            }
            node = node.next;
        }
        return newhead;
    }
}

Linked List Cycle leetcode

Given a linked list, determine if it has a cycle in it.
Follow up:
Can you solve it without using extra space?
用双指针法, 如果faster 和slower最后遇到了则有环

时间O(n) 空间O(1)
对于是否相遇的参考:转自http://www.cnblogs.com/springfor/p/3862102.html
假设Faster确实把Slower超了而且他俩还没相遇(类似Faster一下迈了2步,Slower一下迈了一步,Faster超了Slower,但是俩人并没遇上)。那么就假设Faster现在在 i+1 位置而Slower在 i 位置。那么前一时刻,Slower肯定是在 i-1 位置,而Faster肯定在(i+1)-2位置,所以前一时刻,俩人都在 i-1 位置,相遇了。
还有一种情况就是Faster在i+2位置而slower在i位置,那么前一时刻,Faster在i位置,而Slower在 i-1位置。这样问题又回归到上面那种情况了(再往前一时刻,Faster在i-2位置,Slower在i-1-1位置,相遇)。
所以,这就证明Runner和Faster在有环的链表中肯定会相遇。

public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null){
            return false;
        }
        ListNode faster = head, slower = head;
        while (faster.next != null && faster.next.next != null){
            faster = faster.next.next;
            slower = slower.next;
            if (faster == slower){
                return true;
            }
        }
        return false;
    }
}

Merge k Sorted Lists leetcode

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
用分治法的mergesort的思想 把lists分成小list 最后合并
merge的方法就是之前merge 2 sorted list的方法

时间复杂度O(nlog(n)) 计算方法用主定理


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
  
        if (lists.length == 0 || lists == null){
            return null;
        }
        return sort(lists, 0, lists.length - 1);
    }
    private ListNode sort(ListNode[] lists, int start, int end){
        if (start == end){
            return lists[start];
        }
        int mid = (start + end) / 2;
        ListNode left = sort(lists, start, mid);
        ListNode right = sort(lists, mid + 1, end);
        return merge(left, right);
    }
    private ListNode merge(ListNode left, ListNode right){
        ListNode dummy = new ListNode(0);
        ListNode point = dummy;
        while (left != null && right != null){
            if (left.val < right.val){
                point.next = left;
                left = left.next;
            } else {
                point.next = right;
                right = right.next;
            }
            point = point.next;
        }
        if (left != null){
            point.next = left;
        } else {
            point.next = right;
        }
        return dummy.next;
    }
}

2015年4月28日星期二

Remove Nth Node From End of List leetcode

Given a linked list, remove the nth node from the end of list and return its head.
For example,
   Given linked list: 1->2->3->4->5, and n = 2.

   After removing the second node from the end, the linked list becomes 1->2->3->5.

首先先让faster从起始点往后跑n步。
然后再让slower和faster一起跑,直到faster==null时候,slower所指向的node就是需要删除的节点。
注意:慢指针要在dummy上而不是head上 因为可能head位的数值被删除
return也要return dummy.next 因为head可能被删除

时间O(n) 空间O(1)

public class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (n <= 0){
            return null;
        }
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode faster = head;
        ListNode slower = dummy;
        for (int i = 0; i < n; i++){
            if (faster == null){
                return null;
            }
            faster = faster.next;
        }
        while (faster!= null){
            faster = faster.next;
            slower = slower.next;
        }
        slower.next = slower.next.next;
        return dummy.next;
        
    }
}

Reorder List leetcode

Given a singly linked list LL0L1→…→Ln-1Ln,
reorder it to: L0LnL1Ln-1L2Ln-2→…
You must do this in-place without altering the nodes' values.

Example
For example,
Given 1->2->3->4->null, reorder it to 1->4->2->3->null.
第一步,将链表分为两部分。时间O(n)
第二步,将第二部分链表逆序。时间O(n)
第三步,将链表重新组合。时间O(n)
总体时间O(n) 空间O(1)

public class Solution {
    /**
     * @param head: The head of linked list.
     * @return: void
     */
    public void reorderList(ListNode head) {  
        if (head == null || head.next == null){
            return ;
        }
        ListNode mid = findmid(head);
        ListNode tail = reverse(mid.next);
        mid.next = null;
        merge(head, tail);
    }
    private ListNode findmid(ListNode head){
        ListNode slow = head;
        ListNode fast = head.next;
        while (fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    private ListNode reverse(ListNode head){
        ListNode prev = null;
        while (head != null){
            ListNode tem = head.next;
            head.next = prev;
            prev = head;
            head = tem;
        }
        return prev;
    }
    private void merge(ListNode head, ListNode tail){
        ListNode dummy = new ListNode(0);
        while (head != null && tail != null){
            dummy.next = head;
            head = head.next;
            dummy = dummy.next;
            dummy.next = tail;
            tail = tail.next;
            dummy = dummy.next;
        }
        if (head != null){
            dummy.next = head;
        } else {
            dummy.next = tail;
        }
    }
}

Sort List leetcode

Sort a linked list in O(n log n) time using constant space complexity.
分析: O(nlogn)就是用merge sort或者quick sort
用merge sort首先考虑找中点---用快慢指针的方法
merge-- 用merge 2 linkedlist方法

public class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null){
            return head;
        }
        ListNode mid = findmid(head);
        ListNode right = sortList(mid.next);
        mid.next = null;
        ListNode left = sortList(head);
        return merge(left, right);
    }
    private ListNode findmid(ListNode head){
        ListNode slow = head;
        ListNode fast = head.next;
        while (fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    private ListNode merge(ListNode head1, ListNode head2){
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while (head1 != null && head2 != null){
            if (head1.val < head2.val){
                tail.next = head1;
                tail = tail.next;
                head1 = head1.next;
            } else {
                tail.next = head2;
                tail = tail.next;
                head2 = head2.next;
            }
        }
        if (head1 != null){
            tail.next = head1;
        } else {
            tail.next = head2;
        }
        return dummy.next;
    }
}

2015年4月27日星期一

Recover Binary Search Tree leetcode

Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
这道题是要求恢复一颗有两个元素调换错了的二叉查找树。中序遍历BST 然后找到逆序。
1. 中序遍历相邻的两个元素被调换了,很容易想到就只需会出现一次违反情况,只需要把这个两个节点记录下来最后调换值就可以;
2. 如果是不相邻的两个元素被调换了,会发生两次逆序的情况,那么这时候需要调换的元素应该是第一次逆序前面的元素,和第二次逆序后面的元素。比如1234567,1和5调换了,会得到5234167,逆序发生在52和41,我们需要把4和1调过来,那么就是52的第一个元素,41的第二个元素调换即可。
时间复杂度是O(n),空间是栈大小O(logn)

public class Solution {
    TreeNode pre, first, second;
    public void recoverTree(TreeNode root) {
        pre = null;
        first = null;
        second = null;
        inorder(root);
        if (first != null && second != null){
            int tem = first.val;//只调换val 不是node
            first.val = second.val;
            second.val = tem;
        }
    }
    private void inorder(TreeNode root){
        if (root == null){
            return;
        }
        inorder(root.left);
        if (pre == null){
            pre = root;//初始化pre
        } else {
            if (pre.val > root.val){
                if (first == null){
                    first = pre;//第一个逆序点
                } 
                second = root;//如果相邻第一次就找全, 如果不相邻则遍历完后找到第二个逆序点
            }
            pre = root;//给pre赋值
        }
        inorder(root.right);
    }
}
//方法2 不用全局变量
public class Solution {
    public void recoverTree(TreeNode root) {
        if (root == null) {
            return;
        }
        ArrayList<TreeNode> res = new ArrayList<TreeNode>();
        ArrayList<TreeNode> tem = new ArrayList<TreeNode>();
        tem.add(null);
        helper(root, res, tem);
        if (res.size() > 0) {
            int save = res.get(0).val;
            res.get(0).val = res.get(1).val;
            res.get(1).val = save;
        }
        
    }
    public void helper(TreeNode root, ArrayList<TreeNode> res, ArrayList<TreeNode> tem) {
        if (root == null) {
            return;
        }
        helper(root.left, res, tem);
        if (tem.get(0) != null && root.val < tem.get(0).val) {
            if (res.size() == 0) {
                res.add(tem.get(0));
                res.add(root);
            } else {
                res.set(1, root);
            }
        }
        tem.set(0, root);
        helper(root.right, res, tem);
    }
}

Binary Search Tree Iterator leetcode

Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST.
Calling next() will return the next smallest number in the BST.
Note: next() and hasNext() should run in average O(1) time and uses O(h) memory, where h is the height of the tree.
这道题相当于用stack来实现递归的中序遍历。不能递归的都用stack来实现
每个next都相当于返回当前root的子树的最小结点, 所以一直向左找到最小点返回, 下一个点是当前点的右子树(已经没有左子树了)
判定时候的cur!= null是保证判定root点时候

public class BSTIterator {
    private Stack<TreeNode> stack = new Stack<TreeNode>();
    private TreeNode cur;
    public BSTIterator(TreeNode root) {
        cur = root;
    }

    /** @return whether we have a next smallest number */
    public boolean hasNext() {
        return cur != null || !stack.isEmpty();
    }

    /** @return the next smallest number */
    public int next() {
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
        cur = stack.pop();
        TreeNode node = cur;
        cur = node.right;
        return node.val;
    }
}

2015年4月26日星期日

Search Range in Binary Search Tree

Given two values k1 and k2 (where k1 < k2) and a root pointer to a Binary Search Tree. Find all the keys of tree in range k1 to k2. i.e. print all x such that k1<=x<=k2 and x is a key of given BST. Return all the keys in ascending order.
Example
For example, if k1 = 10 and k2 = 22, then your function should print 12, 20 and 22.
          20
       /        \
    8           22
  /     \
4       12
1. 如果root.val > k1 递归的找他的左子树
2. 如果root.val 在k1, k2之间 添加root到result
3. 如果root.val < k2 递归找他的右子树
public class Solution {
    /**
     * @param root: The root of the binary search tree.
     * @param k1 and k2: range k1 to k2.
     * @return: Return all keys that k1<=key<=k2 in ascending order.
     */
    public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        helper(root, k1, k2, result);
        return result;
    }
    private void helper(TreeNode root, int k1, int k2, ArrayList<Integer> result){
        if (root == null){
            return;
        }
        if (root.val > k1){
            helper(root.left, k1, k2, result);
        }
        if (root.val >= k1 && root.val <= k2){
            result.add(root.val);
        }
        if (root. val < k2){
            helper(root.right, k1, k2, result);
        }
    }
}

Validate Binary Search Tree leetcode

Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
  • The left subtree of a node contains only nodes with keys less than the node's key.
  • The right subtree of a node contains only nodes with keys greater than the node's key.
  • Both the left and right subtrees must also be binary search trees.
bfs中序遍历整个树, 因为BST所以是递增的 
根据这一点我们只需要中序遍历这棵树,然后保存前驱结点,每次检测是否满足递增关系即可。注意以下代码我么用一个一个变量的数组去保存前驱结点,原因是java没有传引用的概念,如果传入一个变量,它是按值传递的,所以是一个备份的变量,改变它的值并不能影响它在函数外部的值,算是java中的一个小细节。
一次树的遍历,所以时间复杂度是O(n),空间复杂度是O(logn)。
public class Solution {
    public boolean isValidBST(TreeNode root) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        res.add(null);
        return helper(root, res);
    }
    public boolean helper(TreeNode root, ArrayList<Integer> res){
        if (root == null){
            return true;
        }
        boolean left = helper(root.left, res);
        if (res.get(0) != null && res.get(0) >= root.val){//显示left和root比, 存入root, 然后root和right比 存入right
            return false;
        }
        res.set(0, root.val);
        boolean right = helper(root.right, res);
        return left && right;
    }
}


2015年4月23日星期四

Binary Tree Inorder Traversal leetcode

Given a binary tree, return the inorder traversal of its nodes' values.
For example:
Given binary tree {1,#,2,3},
   1
    \
     2
    /
   3
Inorder: return [1,3,2]. 左中右
addAll 是因为arraylist result 里面应该添加int
第一种是递归的算法,时间复杂度是O(n), 而空间复杂度则是递归栈的大小,即O(logn)。
第二种是迭代的算法, 用栈来实现。 时间复杂度是O(n), 空间O(logn)
第三种是分治算法

public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null) {
            return res;
        }
        helper(res, root);
        return res;
    }
    public void helper(List<Integer> res, TreeNode root) {
        if (root == null) {
            return;
        }
        helper(res, root.left);
        res.add(root.val);
        helper(res, root.right);
    }
}
public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null) {
            return res;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        while (!stack.isEmpty() || root != null) {
            if (root != null) {
                stack.push(root);
                root= root.left;
            } else {
                root = stack.pop();
                res.add(root.val);
                root = root.right;
            }
        }
        return res;
    }
}
public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null) {
            return res;
        }
        List<Integer> left = inorderTraversal(root.left);
        List<Integer> right = inorderTraversal(root.right);
        res.addAll(left);
        res.add(root.val);
        res.addAll(right);
        return res;    
    }
    
    
}

Binary Tree Zigzag Level Order Traversal leetcode

Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).
For example:
Given binary tree {3,9,20,#,#,15,7},
    3
   / \
  9  20
    /  \
   15   7
return its zigzag level order traversal as:
[
  [3],
  [20,9],
  [15,7]
]
用一个flag记录是否要reverse 一层reverse 一层不reverse添加
判断flag要在for 循环外面
时间O(n) 空间O(n)
public class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if (root == null) {
            return res;
        }
        boolean flag = true;
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> tem = new ArrayList<Integer>();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
                if (flag) {
                    tem.add(node.val);
                } else {
                    tem.add(0,node.val);
                }
            }
            flag = !flag;
            res.add(tem);
        }
        return res;
    }
}

Binary Tree Level Order Traversal II leetcode

Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root).
For example:
Given binary tree {3,9,20,#,#,15,7},
    3
   / \
  9  20
    /  \
   15   7
return its bottom-up level order traversal as:
[
  [15,7],
  [9,20],
  [3]
]
跟之前题一样, 只是每次添加时候都添加到0位置.做这道题范2了把for循环里的treenode 又起名为root 搞得出错了
第二种方法想法比较简单 但是要声明两次level的组
时间O(n) 空间O(n)

public class Solution {
    public ArrayList<ArrayList<Integer>> levelOrderBottom(TreeNode root) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        if (root == null){
            return result;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        while (!queue.isEmpty()){
            ArrayList<Integer> level = new ArrayList<Integer>();
            int size = queue.size();
            for (int i = 0; i < size; i++){
                TreeNode cur = queue.poll();
                level.add(cur.val);
                if (cur.left != null){
                    queue.offer(cur.left);
                }
                if (cur.right != null){
                    queue.offer(cur.right);
                }
            }
            result.add(0, level);
        }
        return result;
    }
}


public class Solution {
    public ArrayList<ArrayList<Integer>> levelOrderBottom(TreeNode root) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        if (root == null){
            return result;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        int curlevel = 1;
        int nextlevel = 0;
        ArrayList<Integer> level = new ArrayList<Integer>();
        while (!queue.isEmpty()){
            
            TreeNode cur = queue.poll();
            level.add(cur.val);
            curlevel--;
            if (cur.left != null){
                queue.offer(cur.left);
                nextlevel++;
            }
            if (cur.right != null){
                queue.offer(cur.right);
                nextlevel++;
            }
            if (curlevel == 0){
                curlevel = nextlevel;
                nextlevel = 0;
                result.add(0, level);
                level = new ArrayList<Integer>();
            }
        }
        return result;
    }
}

2015年4月22日星期三

Binary Tree Level Order Traversal leetcode

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).
For example:
Given binary tree {3,9,20,#,#,15,7},
    3
   / \
  9  20
    /  \
   15   7
return its level order traversal as:
[
  [3],
  [9,20],
  [15,7]
]
这道题是广度优先搜索的模板,BFS用queue来实现
时间O(n) 空间O(n)

要注意:a.有while和for双重循环 
b.每次都要给size付一个新值(如果不赋值queue.size在不停变化)
c.queue add 和 delete 是.offer 和.poll 
d. queue为什么用linkedlist实现???---Queue是接口, LinkedList可以实现此接口。

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res= new ArrayList<List<Integer>>();
        if (root == null) {
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        while (!queue.isEmpty() ) {
            int size = queue.size();
            List<Integer> tem = new ArrayList<Integer>();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                tem.add(node.val);
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
            res.add(tem);
        }
        return res;
    }
}

Lowest Common Ancestor lintcode

Given the root and two nodes in a Binary Tree. Find the lowest common ancestor(LCA) of the two nodes.
The lowest common ancestor is the node with largest depth which is the ancestor of both nodes.
Example
        4
    /     \
  3         7
          /     \
        5         6
For 3 and 5, the LCA is 4.
For 5 and 6, the LCA is 7.
For 6 and 7, the LCA is 7.
这道题还是用分治法, 从最底下往上遍历,当找到一个所给node,向上传递node, 如果没找到就传递null。 上一层的parent会check自己的左右子树是否都有返回值,a.如果都有值那么这个node就是LCA, 向上传递这个node一直到根节点。b. 只有一个子树有值, 那么向上传递这个子树。c.若果左右都没有, 向上传递null
/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     * @param root: The root of the binary search tree.
     * @param A and B: two nodes in a Binary.
     * @return: Return the least common ancestor(LCA) of the two nodes.
     */
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {
        if (root == null){
            return null;
        }
        if (root == A || root == B){
            return root;//当找到一中一个node, 向上传递这个node
        }
        TreeNode left = lowestCommonAncestor(root.left, A, B);
        TreeNode right = lowestCommonAncestor(root.right, A, B);
        if (left != null && right != null){//check左右,如果左右分别包含两个node则这个root就是LCA, 向上传递这个node
            return root;
        } else if (left != null){//只有左边有node,向上传递此node
            return left;
        } else if (right != null){
            return right;
        } else{//左右边都没有node 传递null
            return null;
        }
    }
}

2015年4月21日星期二

Binary Tree Maximum Path Sum leetcode

Given a binary tree, find the maximum path sum.
The path may start and end at any node in the tree.
For example:
Given the below binary tree,
       1
      / \
     2   3
Return 6.


这道题包涵root在内的最大值有四种情况:
 1.root本身(可能有负数存在的情况)
 2. root+左子树
 3.root+ 右子树
 4.root + 左子树 + 右子树 解题
因为需要一个位置来存储最大值, 所以新建一个helper函数 把最大值存入一个数组里, 这样便利完整个树之后最大值久得到了。
这里注意result的初始值应该是Integer.MIN_VALUE

解题思路就是找到最大的一条更新到result[0]里面 (java无法按引用传,就只能建立一个数组
1,2,3 三部需要用来当前root分支的最大值(4情况不算是root的分支了), 所以要传回去

算法的本质还是一次树的遍历,所以复杂度是O(n)。而空间上仍然是栈大小O(logn)。



public class Solution {
    public int maxPathSum(TreeNode root) {
        int[] result = new int[1];
        result[0] = Integer.MIN_VALUE;
        helper(result, root);
        return result[0];
    }
    public int helper(int[] result, TreeNode root){
        if (root == null){
            return 0;
        }
        //divide
        int left = helper(result, root.left);
        int right = helper(result, root.right);
        //Conquer
        int max = Math.max(root.val, Math.max(root.val + left, root.val + right));//找1,2,3的最大值返回
        result[0] = Math.max(result[0], Math.max(max, root.val + left + right));//把4步里的最大值和result[0]比较,返回最大的为result[0]
        return max;
    }
}

Balanced Binary Tree leetcode

Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
这道题跟之前一道是一样的 就是找binary tree的深度,用分治法解题。但是要返回的是Boolean值 所以就写一个helper程序 在树平衡时候返回深度 不平衡就返回-1 . 然后用Boolean判定最后返回是否为-1
算法的时间是一次树的遍历O(n),空间是栈高度O(logn)。

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isBalanced(TreeNode root) {
        return checkBalance(root) != -1;
    }
    public int checkBalance(TreeNode root){
        if (root == null){
            return 0;
        }
        int left = checkBalance(root.left);
        int right = checkBalance(root.right);
        if (left == -1|| right == -1|| Math.abs(left - right) > 1){
            return -1;
        }//如果left或者right不平衡就网上返回-1;
        return Math.max(left, right) + 1;
    }
}

Maximum Depth of Binary Tree leetcode & Divide and conquer模板


Divide and Conquer 模板

public class Solution {
    public ResultType traversal(TreeNode root) {
        // null or leaf
        if (root == null) {
            // do something and return;
        }

        // Divide
        ResultType left = traversal(root.left);
        ResultType right = traversal(root.right);

        // Conquer
        ResultType result = Merge from left and right.
        return result;
    }
}
Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

public class Solution {
    public class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null){
            return 0;
        }
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        return Math.max(left, right) + 1//深度=子数深度+1;
    }
}

//非递归解法 BFS
public class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        int res = 0;
        while (!queue.isEmpty()){
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
            res += 1;
        }
        return res;
    }
}

2015年4月19日星期日

Binary Tree Preorder Traversal leetcode

Given a binary tree, return the preorder traversal of its nodes' values.
Example
Note
Given binary tree {1,#,2,3},
   1
    \
     2
    /
   3

return [1,2,3].
preorder 左 --中-- 右
第一种方法:迭代iteratively算法的时间复杂度是O(n), 而空间复杂度则是递归栈的大小,即O(logn)
public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null) {
            return res;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        while (root != null || !stack.isEmpty()) {
            if (root != null) {
                stack.push(root);
                res.add(root.val);
                root = root.left;
            } else {
                root = stack.pop();
                root = root.right;
            }
        }
        return res;
    }
}


第二种方法: 递归(Recursive算法的时间复杂度是O(n), 而空间复杂度则是递归栈的大小,即O(logn)
public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        traverse(root, result);
        return result;
        
    }
    private void traverse(TreeNode root, ArrayList<Integer> result){
        if (root == null){
            return;
        }
        result.add(root.val);
        traverse(root.left, result);
        traverse(root.right, result);
    }
}

第三种 分治(Divide & Conquer)
Generally, D&C questions would do 2 things at same time:
  1. Divide – For binary tree, it mean solve left child, and solve right child
  2. Conquer – return result value
public class Solution {
    public ArrayList<Integer> preorderTraversal(TreeNode root) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        if (root == null){
            return result;
        }
        //divide
        ArrayList<Integer> left = preorderTraversal(root.left);
        ArrayList<Integer> right = preorderTraversal(root.right);
        // Conquer
        result.add(root.val);
        result.addAll(left);//用addall方法是因为left类型是arraylist不是int
        result.addAll(right);
        return result;
        
    }
}

三部反转法--Recover Rotated Sorted Array

Given a rotated sorted array, recover it to sorted array in-place.
Example
[4, 5, 1, 2, 3] -> [1, 2, 3, 4, 5]
Challenge
In-place, O(1) extra space and O(n) time.
『三步翻转法』,以[4, 5, 1, 2, 3]为例。
  1. 首先找到分割点51
  2. 翻转前半部分4, 55, 4,后半部分1, 2, 3翻转为3, 2, 1。整个数组目前变为[5, 4, 3, 2, 1]
  3. 最后整体翻转即可得[1, 2, 3, 4, 5]
由以上3个步骤可知其核心为『翻转』的in-place实现。使用两个指针,一个指头,一个指尾,使用for循环移位交换即可。
注意:arraylist 里面存取数值要用 arraylist.get()/.set() 

public class Solution {
    /**
     * @param nums: The rotated sorted array
     * @return: The recovered sorted array
     */
    public void recoverRotatedSortedArray(ArrayList<Integer> nums) {
        // write your code
        for (int p =1; p < nums.size(); p++){
            if (nums.get(p - 1) > nums.get(p)){
                reverse(nums, 0, p - 1);
                reverse(nums, p, nums.size() - 1);
                reverse(nums, 0, nums.size() - 1);
                return;
            }
        }
    }

    private void reverse(ArrayList<Integer> nums, int start, int end){
        for (int i = start, j = end; i < j; i++, j--){
            int tem = nums.get(i);
            nums.set(i, nums.get(j));
            nums.set(j, tem);
        }
    }
}



2015年4月16日星期四

Reverse Words in a String leetcode

Given an input string, reverse the string word by word.
For example,
Given s = "the sky is blue",
return "blue is sky the".
解题思路:
先用string.split()把string分解成一个个的字符, 把字符存放在一个list里面. 然后从后往前取字符(要加上空格)添加到一个新的string里.
要注意可能以前的string里面有很多空格 所以在list里面取字符时候要判定如果是空格就舍弃.
时间上split操作是O(N),再一次扫描获得结果,也是O(N)。空间上使用了一个String[] 和StringBuffer,也是O(N)

public class Solution {
    public String reverseWords(String s) {
        if (s == null || s.length() == 0){
            return s;
        }
        s.trim();
        String [] str = s.split(" ");
        StringBuilder tem = new StringBuilder();
        for (int i = str.length - 1; i >= 0; i--){
            if (str[i].length() == 0){
                continue;
            }
            tem.append(str[i] + " ");
        }
        return tem.toString().trim();//因为每次都有加空格 所以tem最结尾有一个空格
    }                               // 需要trim来去掉空格
}
参考:http://www.cnblogs.com/EdwardLiu/p/4019970.html

【转】 String,StringBuffer与StringBuilder的区别

String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)

 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
 而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
 String S1 = “This is only a” + “ simple” + “ test”;
 StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
 String S1 = “This is only a” + “ simple” + “test”; 其实就是:
 String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做

在大部分情况下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。
在大部分情况下 StringBuilder > StringBuffer
java.lang.StringBuilde
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

Median of Two Sorted Arrays leetcode

第一种方法 先把两个数组合并, 然后返回新数组的中间值 时间复杂度 O(m + n) 空间 O(m + n)
public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        int[] tem = new int[m + n];
        int idx1 = m - 1;
        int idx2 = n - 1;
        int idx = idx1 + idx2 + 1;
        while (idx1 >= 0 && idx2 >= 0) {
            if (nums1[idx1] >= nums2[idx2]) {
                tem[idx--] = nums1[idx1--];
            } else {
                tem[idx--] =  nums2[idx2--];
            }
        }
        if (idx2 < 0) {
            for (int i = idx1; i >= 0; i--) {
                tem[idx--] = nums1[i];
            }
        }
        if (idx1 < 0) {
            for (int i = idx2; i>= 0; i--) {
                tem[idx--] = nums2[i];
            }
        }
        if ((m + n) % 2 == 1) {
            return tem[(m + n) / 2 ];
        } else {
            return (tem[(m + n) / 2] + tem[(m + n) / 2 - 1]) / 2.0;
        }
    }
}

可以依照:寻找一个unioned sorted array中的第k大(从1开始数)的数。因而等价于寻找并判断两个sorted array中第k/2(从1开始数)大的数。
特殊化到求median,那么对于奇数来说,就是求第(m+n)/2+1(从1开始数)大的数。
而对于偶数来说,就是求第(m+n)/2大(从1开始数)和第(m+n)/2+1大(从1开始数)的数的算术平均值。

那么如何判断两个有序数组A,B中第k大的数呢?
我们需要判断A[k/2-1]和B[k/2-1]的大小。
如果A[k/2-1]==B[k/2-1],那么这个数就是两个数组中第k大的数。
如果A[k/2-1]<B[k/2-1], 那么说明A[0]到A[k/2-1]都不可能是第k大的数,所以需要舍弃这一半,继续从A[k/2]到A[A.length-1]继续找。当然,因为这里舍弃了A[0]到A[k/2-1]这k/2个数,那么第k大也就变成了,第k-k/2个大的数了。
如果 A[k/2-1]>B[k/2-1],就做之前对称的操作就好。
 这样整个问题就迎刃而解了。

当然,边界条件页不能少,需要判断是否有一个数组长度为0,以及k==1时候的情况。

因为除法是向下取整,并且页为了方便起见,对每个数组的分半操作采取:
int partA = Math.min(k/2,m);
int partB = k - partA; 
 为了能保证上面的分半操作正确,需要保证A数组的长度小于B数组的长度。
总的时间复杂度为O(logk),空间复杂度也是O(logk),即为递归栈大小。在这个题目中因为k=(m+n)/2,所以复杂度是O(log(m+n))。

同时,在返回结果时候,注意精度问题,返回double型的就好。 
public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        int m = A.length;
        int n = B.length;
        if ((m + n) % 2 ==1 ){
            return helper(A, 0, m - 1, B, 0, n - 1, (m + n) / 2 + 1);//k传得是第k个,index实则k-1
        } else {
            return (helper(A, 0, m - 1, B, 0, n - 1, (m + n) / 2 + 1) + helper(A, 0, m - 1, B, 0, n - 1, (m + n) / 2)) / 2.0;
        }
    }
    public int helper(int A[], int i, int i0, int B[], int j, int j0, int k){
        int a = i0 - i + 1;// x现有的A数组长度
        int b = j0 - j + 1;
        if (a > b){ // 如果A数组比B数组长 反过来比较
            return helper(B, j, j0, A, i, i0, k);
        }
        if (a == 0){ //当A数组的值全部比较完的时候
            return B[j + k -  1];//此时的k与原来的k相比已经删除了A的长度 
                                //-1是因为index要-1
        }
        if (k == 1){//此时必须要退出 因为k==1时候已经无法再往下分
            return Math.min(A[i], B[j]);
        }
        int posA = Math.min(k/2, a);//防止此时k/2溢出
        int posB = k - posA;
        if (A[posA + i -1] == B[posB + j - 1]){// 如果相等 则中心元素就为次相等值
            return A[posA + i - 1];
        } else if(A[posA + i -1] > B[posB + j - 1]){
            return helper(A, i, i0, B, posB + j, j0, k - posB);//删除前posB个元素
        } else{
            return helper(A, posA + i, i0, B, j, j0, k - posA);
        }
    }
}