leetcode最优解整理2(Linked list/ Stack/Queue/Array/HashTable/ Tree/bfs/union find)

linked list

2. Add Two Numbers
相加两个非空的linked lists,每个节点只有一位(需进位) 
思路:循环中,进位分开和l1.val、l2.val相加(长度不一)。新链表至少两指针,其长度可能大于l1或l2(进位)
	public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
		ListNode res = new ListNode(0);
		ListNode p = res;
		int carry = 0;
		while(l1 != null || l2 != null || carry != 0) { // bug point
			if (l1 != null) {
				carry += l1.val;
				l1 = l1.next;
			}
			if (l2 != null) {
				carry += l2.val;
				l2 = l2.next;
			}
			p.next = new ListNode(carry % 10);
			carry /= 10;
			p = p.next;
		}
		return res.next;
	}
19. Remove Nth Node From End of List
fast,slow
要考虑n小于链表结点个数的情况,考虑n为0
	public ListNode removeNthFromEnd(ListNode head, int n) {
		if (head == null) {
			return head;
		}
		int count = 1;
		ListNode fakeHead = new ListNode(-1);
		fakeHead.next = head;
		ListNode fast = head, slow = fakeHead;
		while (count < n) {
			fast = fast.next;
			count++;
		}
		while (fast.next != null) {
			fast = fast.next;
			slow = slow.next;
		}
		slow.next = slow.next.next;
		return fakeHead.next;
	}
21. Merge Two Sorted Lists
	public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
		ListNode head = new ListNode(-1);
		ListNode f = head;
		while (l1 != null && l2 != null) {
			if (l1.val <= l2.val) {
				f.next = l1;
				f = f.next;
				l1 = l1.next;
			} else {
				f.next = l2;
				f = f.next;
				l2 = l2.next;
			}
		}
		if (l1 != null) {
			f.next = l1;
		}
		if (l2 != null) {
			f.next = l2;
		}
		return head.next;
    }
23. Merge k Sorted Lists
思路:k个链表的合并和两个没有太大的区别,主要的差别在于一次要求解k个元素的最小值。
每次求最小值的k个元素其实在两次求解之间只会变化一个数,因此可以用最小堆。
PriorityQueue的排序,每次取一个链中的一点
	public ListNode mergeKLists(ListNode[] lists) {
		if (lists == null || lists.length == 0)
			return null;
		if (lists.length == 1)
			return lists[0];
		PriorityQueue<ListNode> heap = new PriorityQueue<>(new Comparator<ListNode>() {
			public int compare(ListNode o1, ListNode o2) {
				return o1.val - o2.val;
			}
		});
		ListNode head = new ListNode(0), rear = head;
		head.next = null;
		for (ListNode node : lists) {
		      if (node != null)
				heap.offer(node); // add
		}

		while (!heap.isEmpty()) {
			rear.next = heap.poll();
			rear = rear.next;
			if (rear.next != null)
				heap.offer(rear.next); // 从第二个node开始又是一个新链
		}
		rear.next = null;
		return head.next;
	}
24. Swap Nodes in Pairs
swap every two adjacent nodes and return its head( 1->2->3->4 ——>2->1->4->3
public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
        	return head;
        }
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        
        ListNode cur = dummy;
        while (cur.next != null && cur.next.next != null) {
        	ListNode l1 = cur.next;
        	ListNode l2 = cur.next.next;
        	l1.next = l2.next;
        	cur.next = l2;
        	l2.next = l1;
        	cur = cur.next.next;
        }
        return dummy.next;
    }
25. Reverse Nodes in k-Group
每k个内部进行reverse, 1->2->3->4->5,   k  = 3,则 3->2->1->4->5
思路:递归。每次更新head到第k个,第k + 1个已由递归返回。
	public ListNode reverseKGroup2(ListNode head, int k) {
	    ListNode cur = head;
	    int count = 0;
	    while (cur != null && count != k) {
	        cur = cur.next;
	        count++;
	    }
	    if (count == k) {
	        cur = reverseKGroup(cur, k);
	        while (count-- > 0) { 
	            ListNode tmp = head.next;
	            head.next = cur; 
	            cur = head;
	            head = tmp; 
	        }
	        head = cur; // do not forget
	    }
	    return head;
	}
61. Rotate List 
Given  1->2->3->4->5->NULL and  k =  2,
return  4->5->1->2->3->NULL.每个点都往右挪k位

思路:形成一个环,找到新head再断开即可。也可以fast,slow两个指针
public ListNode rotateRight(ListNode head, int k) {
		if (head == null || head.next == null) {
			return head;
		}
        int count = 1;
        ListNode tail= head;
        while (tail.next != null) {
        	count++;
        	tail = tail.next;
        }
        k = k % count;
        if (k == 0) {
        	return head;
        }
        tail.next = head;
        k = count - k;
        for (int i = 1; i <= k; i++) {
        	head = head.next;
        	tail = tail.next;
        }
        tail.next = null;
        return head;
    }
82. Remove Duplicates from Sorted List II
Given  1->2->3->3->4->4->5 , return  1->2->5 . Given  1->1->1->2->3 , return  2->3 .
思路:两指针。bug点:while循环时未判断fast!=null,因为当fast为null时,调用fast.next产生NullPointerException
public ListNode deleteDuplicates(ListNode head) {
		if (head == null || head.next == null) return head;
        ListNode fakehead = new ListNode(-1);
        ListNode slow = fakehead, fast = head;
        fakehead.next = head;
        while (fast != null && fast.next != null) {
        	if (fast.next.val == slow.next.val) {
        		while (fast.next != null && fast.next.val == slow.next.val) {
        			fast = fast.next;
        		}
        		slow.next = fast.next;
        	} else {
        	    slow = slow.next;
        	}
        	
        	fast = fast.next;
        }
        return fakehead.next;
	}
83. Remove Duplicates from Sorted List
Given  1->1->2 , return  1->2 . Given  1->1->2->3->3 , return  1->2->3 .

第一个节点不变,不需要fakehead
public ListNode deleteDuplicates(ListNode head) {
		if (head == null || head.next == null) return head;
        ListNode fast = head.next;
        ListNode slow = head;
        while (fast != null) {
        	if (fast.val == slow.val) {
        		slow.next = fast.next;
        		fast = slow.next;
        	} else {
        		fast = fast.next;
        		slow = slow.next;
        	}
        }
        return head;
    }
86. Partition List
Given a linked list and a value  x , partition it such that all nodes less than  x  come before nodes greater than or equal to  x .
如:1-4-3-2-5-2——>1-2-2-4-3-5
思路:两个list
	public ListNode partition(ListNode head, int x) {
		if (head == null || head.next == null) {
			return head;
		}
		ListNode small = new ListNode(-1);
		ListNode newsmallhead = small; // head不存储数据
		ListNode big = new ListNode(-1);
		ListNode newbighead = big;
		while (head != null) {
			if (head.val < x) {
				small.next = head;
				small = small.next;
			} else {
				big.next = head;
				big = big.next;
	          }
			head = head.next;
		}
		big.next = null;
		small.next = newbighead.next;
		return newsmallhead.next;
	}
206. Reverse Linked List

	public ListNode reverseList(ListNode head) {
		
		ListNode newhead = null;
		while (head != null) {
			ListNode next = head.next;
			head.next = newhead;
			newhead = head;
			head = next;
		}
		return newhead;
    }
迭代、 归、栈

public ListNode reverseList(ListNode head) {
    return reverseListInt(head, null);
}

private ListNode reverseListInt(ListNode head, ListNode newHead) {
    if (head == null)
        return newHead;
    ListNode next = head.next;
    head.next = newHead;
    return reverseListInt(next, head);
}

92. Reverse Linked List II

Reverse a linked list from position m to n. Do it in-place and in one-pass.

For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,

return 1->4->3->2->5->NULL.

public ListNode reverseBetween(ListNode head, int m, int n) {
			if (m >= n) {
				return head;
			}
			ListNode fakeHead = new ListNode(-1);
			fakeHead.next = head;
			ListNode h = fakeHead;
			int cnt = 1;
	        while (cnt < m) {
	        	h = h.next;
	        	cnt++;
	        }
	        if (h.next == null) {
	        	return head;
	        }
	        
	        ListNode s = h.next;
	        ListNode f = s.next;
	        if (f == null) {
	        	return fakeHead.next;
	        }
			for (int i = m; i < n && f != null; i++) {
				s.next = f.next;
				f.next = h.next;
				h.next = f;
				f = s.next;
			}
			
			return fakeHead.next;
	  }


382. Linked List Random Node

Given a singly linked list, return a random node's value from the linked list. Each node must have the same probability of being chosen.

Follow up:
What if the linked list is extremely large and its length is unknown to you? Could you solve this efficiently without using extra space?

public class Solution {
    ListNode head;
    Random rnd;

    public Solution(ListNode head) {
        this.head = head;
        rnd = new Random();
    }
    
    public int getRandom() {
        int res = -1;
        ListNode h = head;
        for (int i = 1; h != null; i++) {
        	if (rnd.nextInt(i) == 0) {
        		res = h.val;
        	}
        	h = h.next;
        }
        return res;
    }
}

96. Unique Binary Search Trees

Given n, how many structurally unique BST's (binary search trees) that store values 1...n?

For example,
Given n = 3, there are a total of 5 unique BST's.

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

思路:dp,dp[1] = 1 ,dp[2] =2 ,dp[3] = 5, dp[4] =14 ,怎么得到dp[5]呢
对于每一个root node,需要知道有多少种左子树,多少种右子树
First we pick 1 as root, for the left sub tree, there are none; for the right sub tree, we need count how many possible trees are there constructed from {2,3,4,5}, apparently it's the same number as {1,2,3,4}. So the total number of trees under "1" picked as root is dp[0] * dp[4] = 14. (assume dp[0] =1). Similarly, root 2 has dp[1]*dp[3] = 5 trees. root 3 has dp[2]*dp[2] = 4, root 4 has dp[3]*dp[1]= 5 and root 5 has dp[0]*dp[4] = 14. Finally sum the up and it's done.
 public int numTrees(int n) {
    int [] dp = new int[n+1];
    dp[0]= 1;
    dp[1] = 1;
    for(int level = 2; level <=n; level++)
        for(int root = 1; root<=level; root++)
            dp[level] += dp[level-root]*dp[root-1];
    return dp[n];
}








199. Binary Tree Right Side View


Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

For example:
Given the following binary tree,

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

You should return [1, 3, 4].

思路1:按行打印
思路2: 1.Each depth of the tree only select one node. View depth is current size of result list.
public List<Integer> rightSideView(TreeNode root) {
        Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
        
        List<Integer> list = new ArrayList<Integer>();
        if (root == null) {
        	return list;
        }
        queue.add(root);
        while (!queue.isEmpty()) {
        	int size = queue.size();
        	TreeNode t = null;
        	while (size >= 1) {
        		t = queue.poll();
        		if (t.left != null) {
        		  queue.add(t.left);   
        		}
        		if (t.right != null) {
        		  queue.add(t.right);   
        		}
        		size--;
        	}
        	list.add(t.val);
        	
        }
        return list;
    }

public class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> result = new ArrayList<Integer>();
        rightView(root, result, 0);
        return result;
    }
    
    public void rightView(TreeNode curr, List<Integer> result, int currDepth){
        if(curr == null){
            return;
        }
        if(currDepth == result.size()){
            result.add(curr.val);
        }
        
        rightView(curr.right, result, currDepth + 1);
        rightView(curr.left, result, currDepth + 1);
        
    }
}

328. Odd Even Linked List


Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes.

Given 1->2->3->4->5->NULL,return 1->3->5->2->4->NULL.

奇数在偶数之前123456->135246  最优思路:连接135,连接246,然后直接合并两个链表

	public ListNode oddEvenList(ListNode head) {
	    if (head != null) {
	    
	        ListNode odd = head, even = head.next, evenHead = even; 
	    
	        while (even != null && even.next != null) {
	            odd.next = odd.next.next; 
	            even.next = even.next.next; 
	            odd = odd.next;
	            even = even.next;
	        }
	        odd.next = evenHead; 
	    }
	    return head;
	}

143. Reorder List

Given a singly linked list L: L0→L1→…→Ln-1→Ln, reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…

分三步:找到中点,reverse后半部分:1->2->3->4->5->6 to 1->2->3->6->5->4   一一合并两半链表

	public void reorderList(ListNode head) {
	      if (head == null || head.next == null)
	          return;
	      
	      ListNode prev = null, slow = head, fast = head, l1 = head;
	      
	      while (fast != null && fast.next != null) {
	        prev = slow;
	        slow = slow.next;
	        fast = fast.next.next;
	      }
	      
	      prev.next = null;
	      
	      ListNode l2 = reverse(slow);
	      
	      merge(l1, l2);
	 }
	    
	    ListNode reverse(ListNode head) {
	      ListNode prev = null, curr = head, next = null;
	      
	      while (curr != null) {
	        next = curr.next;
	        curr.next = prev;
	        prev = curr;
	        curr = next;
	      }
	      
	      return prev;
	    }
	    
	    void merge(ListNode l1, ListNode l2) {
	      while (l1 != null) {
	        ListNode n1 = l1.next, n2 = l2.next;
	        l1.next = l2;
	        
	        if (n1 == null)
	          break;
	          
	        l2.next = n1;
	        l1 = n1;
	        l2 = n2;
	      }
	    }


Stack

20. Valid Parentheses

bug-free盲点:忘判断stack是否为空

	public boolean isValid(String s) {
		if (s.isEmpty()) {
			return true;
		}
		Stack<Character> stack = new Stack<Character>();
		char[] c = s.toCharArray();
		for (int i = 0; i < c.length; i++) {
			if ((c[i] == ')' && !stack.isEmpty() && stack.peek() == '(') || (c[i] == '}' && !stack.isEmpty() && stack.peek() == '{') || (c[i] == ']' && !stack.isEmpty() && stack.peek() == '[')) {
				stack.pop();
			} else {
				stack.push(c[i]);
			}
		}
		return stack.isEmpty();
	}
32. Longest Valid Parentheses
最优思路:入栈的是index
出栈以后别忘了判断stack是否为空。
	public int longestValidParentheses(String s) {
		Stack<Integer> stack = new Stack<Integer>();
		int left = 0;
		int max  = 0;
		for (int i = 0; i < s.length(); i++) {
			if (s.charAt(i) == '(') {
				stack.push(i);
			} else {
    			if(stack.isEmpty()) {
    				left = i;
    			} else {
    				stack.pop();
    			}
    			if(stack.isEmpty()) max = Math.max(max, i - left);
    			else max = Math.max(max, i - stack.peek());
    		}
		}
		return max;
	}
  public int longestValidParentheses(String s) {
    	Stack<Integer> stack = new Stack<Integer>();
    	int max = 0;
    	stack.push(-1); // 不用判断是否为空,记得i - stack.peek() - 1
    	for(int i = 0; i < s.length(); i++) {
    		if(s.charAt(i) == ')' && stack.size() != 1 && s.charAt(stack.peek()) == '(') 
    			stack.pop();
    		else {
    			max = Math.max(max, i - stack.peek() - 1);
    			stack.push(i);
    		}
    	}
    	return Math.max(max, s.length() - stack.pop() - 1);
    }
155. Min Stack
两个stack
public class MinStack {

        Stack<Integer> mainStack = new Stack<Integer>();
        Stack<Integer> minStack = new Stack<Integer>();
        
        public void push(int x) {
            mainStack.push(x);
            if (minStack.empty()) {
                minStack.push(x);
            } else if (minStack.peek() >= x) {
                minStack.push(x);
            }
        }
    
        public void pop() {
            int poppedElement = mainStack.pop();
            if (poppedElement == minStack.peek()) {
                minStack.pop();
            }
        }
    
        public int top() {
            return mainStack.peek();
        }
    
        public int getMin() {
            return minStack.peek();
        }
     }

只用一个stack的方式。思路:push时,若当前数比min小,先push 当前的min,再push此数。这样pop时,可以判断min是否与pop出的相同,若相同则继续pop,并给min赋值。(所有min保存在stack中)
public class MinStack {
    int min = Integer.MAX_VALUE;
    Stack<Integer> stack = new Stack<Integer>();
    public void push(int x) {
        // only push the old minimum value when the current 
        // minimum value changes after pushing the new value x
        if(x <= min){          
            stack.push(min);
            min=x;
        }
        stack.push(x);
    }

    public void pop() {
        // if pop operation could result in the changing of the current minimum value, 
        // pop twice and change the current minimum value to the last minimum value.
        if(stack.pop() == min) min = stack.pop();
    }

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

    public int getMin() {
        return min;
    }
}

存gap
public class MinStack {
    long min;
    Stack<Long> stack;

    public MinStack(){
        stack=new Stack<>();
    }
    
    public void push(int x) {
        if (stack.isEmpty()){
            stack.push(0L);
            min=x;
        }else{
            stack.push(x-min);//Could be negative if min value needs to change
            if (x<min) min=x;
        }
    }

    public void pop() {
        if (stack.isEmpty()) return;
        
        long pop=stack.pop();
        
        if (pop<0)  min=min-pop;//If negative, increase the min value
        
    }

    public int top() {
        long top=stack.peek();
        if (top>0){
            return (int)(top+min);
        }else{
           return (int)(min);
        }
    }

    public int getMin() {
        return (int)min;
    }
}






71. Simplify Path
简化路径
path  =  "/home/" , =>  "/home"
path  =  "/a/./b/../../c/" , =>  "/c"

未考虑输入为,此时输出应为/
bug point :一定记得判断stack是否为空
public String simplifyPath(String path) {
		String[] array = path.split("/");
        Stack<String> stack = new Stack<String>();
        for (int i = 0; i < array.length; i++) {
        	if (array[i].equals(".") || array[i].isEmpty()) {
        		continue;
        	} else if (array[i].equals("..")) {
        		if (!stack.isEmpty()) {
        			stack.pop();
        		}
        	} else {
        		stack.push(array[i]);
        	}
        }
        String s = "";
        for (String s1 : stack) {
        	s += "/" + s1;
        }
        return s.isEmpty() ? "/" : s;
    }
	public String simplifyPath(String path) {
	    Deque<String> stack = new LinkedList<>();
	    Set<String> skip = new HashSet<>(Arrays.asList("..",".",""));
	    for (String dir : path.split("/")) {
	        if (dir.equals("..") && !stack.isEmpty()) stack.pop();
	        else if (!skip.contains(dir)) stack.push(dir);
	    }
	    String res = "";
	    for (String dir : stack) res = "/" + dir + res;
	    return res.isEmpty() ? "/" : res;
	}

Queue

225. Implement Stack using Queues

Implement the following operations of a stack using queues.

  • push(x) -- Push element x onto stack.
  • pop() -- Removes the element on top of the stack.
  • top() -- Get the top element.
  • empty() -- Return whether the stack is empty.

思路:push()先加入x,再依次加入之前queue中所有的元素

class MyStack 
{
    Queue<Integer> queue;
    
    public MyStack()
    {
        this.queue=new LinkedList<Integer>();
    }
    
    // Push element x onto stack.
    public void push(int x) 
    {
       queue.add(x);
       for(int i=0;i<queue.size()-1;i++)
       {
           queue.add(queue.poll());
       }
    }

    // Removes the element on top of the stack.
    public void pop() 
    {
        queue.poll();
    }

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

    // Return whether the stack is empty.
    public boolean empty() 
    {
        return queue.isEmpty();
    }
}


232.Implement Queues using Stack

思路:用两个栈

public class MyQueue {

    /** Initialize your data structure here. */
	Stack<Integer> stack;
	Stack<Integer> stackRead;
    public MyQueue() {
        stack = new Stack<Integer>();
        stackRead = new Stack<Integer>();
    }
    
    /** Push element x to the back of queue. */
    public void push(int x) {
        stack.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        if (!stackRead.isEmpty()) {
        	return stackRead.pop();
        }
        while (!stack.isEmpty()) {
        	stackRead.push(stack.pop());
        }
        return stackRead.pop();
    }
    
    /** Get the front element. */
    public int peek() {
    	if (!stackRead.isEmpty()) {
        	return stackRead.peek();
        }
    	while (!stack.isEmpty()) {
        	stackRead.push(stack.pop());
        }
        return stackRead.peek();
    }
    
    /** Returns whether the queue is empty. */
    public boolean empty() {
        return stack.isEmpty() && stackRead.isEmpty();
    }
}

class MyQueue {

    Stack<Integer> input = new Stack();
    Stack<Integer> output = new Stack();
    
    public void push(int x) {
        input.push(x);
    }

    public void pop() {
        peek();
        output.pop();
    }

    public int peek() {
        if (output.empty())
            while (!input.empty())
                output.push(input.pop());
        return output.peek();
    }

    public boolean empty() {
        return input.empty() && output.empty();
    }
}







 
 

Array

31. Next Permutation

1,2,31,3,2 3,2,11,2,3 1,1,51,5,1

易错!

思路:从右数,遇到第一个i比i-1大的数(第一个从右数的升序),交换i - 1和右侧降序排列的最小的数(所有排列,无非:先升后降,先降后升,还有升降四种。将最后出现的升序的两个连续数变为降序)

比如12543,交换2和3,然后升序排列542,得13245

public void nextPermutation(int[] nums) {
		int i = nums.length - 1; 
        for (; i > 0; i--) {
        	if (nums[i] > nums[i - 1])
        		break;
        }
        if(i == 0) { // 逆序的后一个是顺序
        	Arrays.sort(nums);
        	return;
        }
        int j = i;
        int num = i;
        for (; j < nums.length; j++) { // 找右侧最小数
        	if (nums[j] > nums[i - 1] && nums[j] < nums[num]) 
        		num = j;
        }
        swap(nums, i - 1, num);
        Arrays.sort(nums, i, nums.length);
    }
	public static void swap(int[] a, int i, int j) {
		a[i] = a[i] + a[j];
		a[j] = a[i] - a[j];
		a[i] = a[i] - a[j];
	}

35. Search Insert Position

easy

public int searchInsert(int[] nums, int target) {
		if (nums.length == 0) {
			return 0;
		}
		int i = 0;
        for (; i < nums.length && target > nums[i]; i++) {
        		
        }
        return i;
    }


39. Combination Sum

given candidate set [2, 3, 6, 7] and target 7

A solution set is:

[[7],[2, 2, 3]](每个数可以使用多次)

	public List<List<Integer>> combinationSum(int[] candidates, int target) {
		List<List<Integer>> res = new ArrayList<>();
		List<Integer> temp = new ArrayList<>();
		Arrays.sort(candidates);
		getCombination(candidates,target,0,0,res,temp);
		return res; 
    }
	public static void getCombination(int[] candidates, int target, int sum, int level, List<List<Integer>> res, List<Integer> temp) {
		if (sum > target) {
			return;
		} else if (sum == target) {
			res.add(new ArrayList<>(temp)); // bug point
			return;
		}
		for (int i = level; i < candidates.length; i++) {
			temp.add(candidates[i]);
			getCombination(candidates, target, sum + candidates[i], i, res, temp);
			temp.remove(temp.size() - 1);
		}
	}
40. Combination Sum II       

[10, 1, 2, 7, 6, 1, 5] and target 8,
A solution set is:

[[1, 7],[1, 2, 5],[2, 6],[1, 1, 6]]
区别于上一个,每个数只使用一次
 public List<List<Integer>> combinationSum2(int[] candidates, int target) {
			List<List<Integer>> re = new ArrayList<List<Integer>>();
	        if (candidates.length < 1) {
	        	return re;
	        }
	        Arrays.sort(candidates);
	        helper(candidates, target, 0, new ArrayList<Integer>(), re, 0);
	        return re;
	    }
		public static void helper(int[] a, int target, int sum, List<Integer> l, List<List<Integer>> re, int level) {
			if (sum > target) {
				return;
			} else if (sum == target) {
				re.add(new ArrayList<Integer>(l));
				return;
			}
			for (int i = level; i < a.length; i++) {
				if (i > level && a[i] == a[i - 1]) { // important
					continue;
				}
				l.add(l.size(), a[i]);
				helper(a, target, sum + a[i], l, re, i + 1);
				l.remove(l.size() - 1);
			}
		}
46. Permutations

无重复数,返回所有数的组合
未bug-free原因:忘记boolean[]初始化全为false

public List<List<Integer>> permute(int[] nums) {
		List<List<Integer>> re = new ArrayList<List<Integer>>();
		List<Integer> l = new ArrayList<Integer>();
		boolean[] visited = new boolean[nums.length];
		
		helper(nums, re, l, visited);
		return re;
	}
	public static void helper(int[] a, List<List<Integer>> re, List<Integer> l, boolean[] v) {
		if (l.size() == a.length) {
			re.add(new ArrayList(l));
			return;
		}
		for (int i = 0; i < a.length; i++) {
			if (!v[i]) {
				l.add(a[i]);
				v[i] = true;
				helper(a, re, l, v);
				l.remove(l.size() - 1);
				v[i] = false;
			}
		}
	}
47. Permutations II

和46唯一区别是元素可以重复

思路就是:只对第一个未被使用的数进行递归。(重复值只能出现在递归内部)

	public List<List<Integer>> permuteUnique(int[] nums) {
		Arrays.sort(nums);
		List<List<Integer>> re = new ArrayList<List<Integer>>();
		List<Integer> l = new ArrayList<Integer>();
		boolean[] visited = new boolean[nums.length];
		helper(nums, re, l, visited);
		return re;
	}
	public static void helper(int[] a, List<List<Integer>> re, List<Integer> l, boolean[] v) {
		if (l.size() == a.length && (!re.contains(l))) {
			re.add(new ArrayList(l));
			return;
		}
		for (int i = 0; i < a.length; i++) {
			if (i > 0 && !v[i - 1] && a[i - 1] == a[i])
				continue;
			if (!v[i]) {
				l.add(a[i]);
				v[i] = true;
				helper(a, re, l, v);
				l.remove(l.size() - 1);
				v[i] = false;
			}
		}
	}

60. Permutation Sequence           

The set [1,2,3,…,n] contains a total of n! unique permutations.求第k个permutation sequence

思路:count[n]表示n个数排列的总数。除第一位,从第二位开始共count[n - 1]种排列;因此第一个index算当前k是第几个count[n - 1]
从第一位开始依次决定当前位的数,以n=3,k=3为例,index为 2/count[2]=1,表示第3个排列的第一个数字为index + 1
public String getPermutation(int n, int k) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(-1);
        int[] count = new int[n + 1];
        count[0] = 1;
        for (int i = 1; i <= n; i++) {
        	count[i] = count[i - 1] * i;
        	list.add(i);
        }
        String res = "";
        k--; // bug point!
        for (int i = 1; i <= n; i++) {
        	int index = k / count[n - i];
        	res += String.valueOf(list.get(index + 1));
        	list.remove(index + 1);
        	k -= count[n - i] * index;
        }
        return res;
}

48. Rotate Image
思路:
 先以对角线为轴交换数,然后逆序二维数组中一维数组的顺序
bug-free
	public void rotate(int[][] matrix) {
		if (matrix.length < 1) {
			return;
		}
		int n = matrix.length;
        for (int i = 0; i < n; i++) {
        	for (int j = 0; j < i; j++) {
        		swap(matrix, i, j, j, i);
        	}
        }
        for (int i = 0; i < n; i++) {
        	for (int j = 0; j < n / 2; j++) {
        		swap(matrix, i, j, i, n - 1 - j);
        	}
        }
    }
	public static void swap(int[][] a, int i1, int j1, int i2, int j2) {
		a[i1][j1] = a[i1][j1] + a[i2][j2];
		a[i2][j2] = a[i1][j1] - a[i2][j2];
		a[i1][j1] = a[i1][j1] - a[i2][j2];
	}
54. Spiral Matrix           

Given the following matrix:

[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]

You should return [1,2,3,6,9,8,7,4,5]


public List<Integer> spiralOrder(int[][] matrix) {
		List<Integer> res = new ArrayList<Integer>();
		if(matrix.length==0) {
			return res;
		}
		
		 int rowBegin = 0;
		 int rowEnd = matrix.length-1;
		 int colBegin = 0;
		 int colEnd = matrix[0].length - 1;
		 while (rowBegin <= rowEnd && colBegin <= colEnd) {
			 for (int j = colBegin; j <= colEnd; j++) { // right
				 res.add(matrix[rowBegin][j]);
			 }
			 rowBegin++;
			 for (int i = rowBegin; i <= rowEnd; i++) { // down
				 res.add(matrix[i][colEnd]);
			 }
			 colEnd--;
			 for (int j = colEnd; j >= colBegin; j--) { // left
				 res.add(matrix[rowEnd][j]);
			 }
			 rowEnd--;
			 for (int i = rowEnd; i >= rowBegin; i--) { // up
				 res.add(matrix[i][colBegin]);
			 }
			 colBegin++;
		 }
		
		return res;
    }
55. Jump Game           

Given an array of non-negative integers, you are initially positioned at the first index of the array.Each element in the array represents your maximum jump length at that position. Determine if you are able to reach the last index.

array,greedy

	public boolean canJump(int[] nums) {
		int n = nums.length;
		boolean[] d = new boolean[n];
		d[0] = true;
		for(int i = 1; i < n; i++) {
			for(int j = i - 1; j >= 0; j--) {
				if(d[j] == true && nums[j] >= i - j) {
					d[i] = true;
					break;
				}
			}
		}
		return d[n - 1];
	}
	public boolean canJump2(int[] nums) {
		int max = 0;
		for (int i = 0; i < nums.length; i++) {
			if (i > max) {
				return false;
			}
			max = Math.max(max, nums[j] + i);
		}
		return true;
	}
本题用一个数 reach 表示能到达的最远下标,一步步走下去,如果发现在 reach 范围之内某处能达到的范围大于 reach,那么我们就用更大的范围来替换掉原先的 reach,这样一个局部的最优贪心策略,在全局看来也是最优的,因为 局部能够到达的最大范围也是全局能够到达的最大范围:
 public boolean canJump(int[] nums) {  
        int reach = nums[0];  
        for(int i = 1; i < nums.length && reach >= i; i++)  
            if(i + nums[i] > reach) reach = i + nums[i];  //贪心策略  
        return reach >= (nums.length-1) ? true : false;  
    }
59. Spiral Matrix II           

Spiral Matrix反过来,返回n对应的matrix

public int[][] generateMatrix(int n) {
        int number = 1;
        int[][] re = new int[n][n];
        int rowBegin = 0, rowEnd = n - 1, colBegin = 0, colEnd = n - 1;
        while (rowBegin <= rowEnd && colBegin <= colEnd) {
        	for (int j = colBegin; j <= colEnd; j++) {
        		re[rowBegin][j] = number++;
        	}
        	rowBegin++;
        	for (int j = rowBegin; j <= rowEnd; j++) {
        		re[j][colEnd] = number++;
        	}
        	colEnd--;
        	for (int j = colEnd; j >= colBegin; j--) {
        		re[rowEnd][j] = number++;
        	}
        	rowEnd--;
        	for (int j = rowEnd; j >= rowBegin; j--) {
        		re[j][colBegin] = number++;
        	}
        	colBegin++;
        }
        return re;
    }

66. Plus One
int[] digits数组表示一个非负数,每一位置存储该数的一位。将该数加一,返回数组

(就是进位),这个解法挺巧妙(遇到进位,将本位置0,上一位加1直接返回,若到最高位,直接新数组最高位置1)
public int[] plusOne(int[] digits) {
	    int n = digits.length;
	    for(int i = n - 1; i >= 0; i--) {
	        if(digits[i] < 9) {
	            digits[i]++;
	            return digits;
	        }
	        digits[i] = 0;
	    }
	    
	    int[] newNumber = new int [n + 1];
	    newNumber[0] = 1;
	    return newNumber;
	}
73. Set Matrix Zeros

in place将每个0元素的对应行和列置0。

思路:o(m + n)的方法很容易想到。

o(1):将matrix[i][j]映射到[0][j]和[i][0]两点上,遍历第二次更新matrix, 另外用fr和fc表示matrix在第一行和第一列是否有0元素。

public void setZeroes(int[][] matrix) {
	    boolean fr = false,fc = false;
	    for(int i = 0; i < matrix.length; i++) {
	        for(int j = 0; j < matrix[0].length; j++) {
	            if(matrix[i][j] == 0) {
	                if(i == 0) fr = true;
	                if(j == 0) fc = true;
	                matrix[0][j] = 0;
	                matrix[i][0] = 0;
	            }
	        }
	    }
	    for(int i = 1; i < matrix.length; i++) {
	        for(int j = 1; j < matrix[0].length; j++) {
	            if(matrix[i][0] == 0 || matrix[0][j] == 0) {
	                matrix[i][j] = 0;
	            }
	        }
	    }
	    if(fr) {
	        for(int j = 0; j < matrix[0].length; j++) {
	            matrix[0][j] = 0;
	        }
	    }
	    if(fc) {
	        for(int i = 0; i < matrix.length; i++) {
	            matrix[i][0] = 0;
	        }
	    }
	}
78. Subsets

Given a set of distinct integers, nums, return all possible subsets.If nums = [1,2,3], a solution is:[[3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], []]

思路:

1. 递归

2. 利用bit,numbers are represented as 0000 0001 0010 0011 0100 每个二进制数,对应数组中每一个位置,右移几位为1,就将数组第几个加入subset。这样每一个subset对应一个答案

	public List<List<Integer>> subsets(int[] nums) {
			Arrays.sort(nums);
	        List<List<Integer>> re = new ArrayList<List<Integer>>();
			re.add(new ArrayList<Integer>());
	        if(nums.length < 1) return re;
	        for(int i = 0; i < nums.length; i++) {
	        	List<Integer> list = new ArrayList<Integer>();
	        	list.add(nums[i]);
	        	re.add(list);
	        	helper(list,re, nums, i + 1);
	        }
	        return re;
	    }
		public static void helper(List<Integer> l, List<List<Integer>> r, int[] nums, int level) {
			if(nums.length == level) return; 
			for(int j = level; j < nums.length; j++) {
				List<Integer> l1 = new ArrayList<Integer>(l);
				l1.add(nums[j]);
				r.add(l1);
				helper(l1, r, nums, j + 1);
			}
		}
	public List<List<Integer>> subsets(int[] nums) {
	        int n = 1 << nums.length;
	        List<List<Integer>> answer = new ArrayList<List<Integer>>();
	        for (int i = 0; i < n; i++) {
	            List<Integer> subset = new ArrayList<Integer>(); // 每个i对应一个位置,用bit找出这些位置即可
	            for (int bit = 0; bit < nums.length; bit++) {
	                if (((i >> bit) & 1) == 1) { // 向右移多少位&1为1
	                	System.out.print("i=" +  i +" bit="+bit +" " +((i >> bit) )+ " and ");
	                	subset.add(nums[bit]);
	                }
	            }
	            answer.add(subset);
	            System.out.println(" subset=" + subset );
	        }
	        return answer;
	    }
90. Subsets II
和上一题不同的是,数组可能有重复值。如: If  nums  =  [1,2,2] , a solution is: [ [2], [1], [1,2,2], [2,2], [1,2], []]
思路:重复的数只能递归进入,不可循环
public List<List<Integer>> subsetsWithDup(int[] nums) {
	Arrays.sort(nums);
        List<List<Integer>> re = new ArrayList<List<Integer>>();
	re.add(new ArrayList<Integer>());
        if(nums.length < 1) return re;
        for(int i = 0; i < nums.length; i++) {
        	if(i >0 && nums[i] == nums[i - 1]) continue;
        	List<Integer> list = new ArrayList<Integer>();
        	list.add(nums[i]);
        	re.add(list);
        	List<List<Integer>> re0 = new ArrayList<List<Integer>>();
        	re0 = helper(list,re0, nums, i + 1);
        	re.addAll(re0);
        }
        return re;
    }
	public static List<List<Integer>> helper(List<Integer> l, List<List<Integer>> r, int[] nums, int level) {
		if(nums.length == level) return r; 
		for(int j = level; j < nums.length; j++) {
			List<Integer> l1 = new ArrayList<Integer>();
			l1.addAll(l);
			l1.add(nums[j]);
			if(!r.contains(l1)) r.add(l1);
			r = helper(l1, r, nums, j + 1);
		}
		return r;
	}
简化:
public List<List<Integer>> subsetsWithDup(int[] nums) {
		Arrays.sort(nums);
		List<List<Integer>> res = new ArrayList<List<Integer>>();
	    List<Integer> each = new ArrayList<Integer>();
	    helper(res, each, 0, nums);
	    return res;
    }
	public void helper(List<List<Integer>> res, List<Integer> each, int pos, int[] n) {
	    if (pos <= n.length) {
	        res.add(each);
	    }
	    int i = pos;
	    while (i < n.length) {
	        each.add(n[i]);
	        helper(res, new ArrayList<Integer>(each), i + 1, n);
	        each.remove(each.size() - 1);
	        i++;
	        while (i < n.length && n[i] == n[i - 1]) {i++;}
	    }
	    return;
	}




79 Word Search

The word can be constructed from letters of horizontally or vertically neighboring. The same letter cell may not be used more than once.

Given board =[  ['A','B','C','E'], ['S','F','C','S'], ['A','D','E','E']]word = "ABCCED", -> returns true,word = "SEE", -> returns true,word = "ABCB", -> returns false.

思路:记得将走过的路标记,将char^256即可


public boolean exist(char[][] board, String word) {
        for (int i = 0; i < board.length; i++) {
        	for (int j = 0; j < board[0].length; j++) {
        		if (board[i][j] == word.charAt(0)) {
        			if (helper(board, word, i, j)) { 
        				return true;
        			}
        		}
        	}
        }
        return false;
    }
	public static boolean helper(char[][] grid, String word, int x, int y) {
		if (word.length() < 1) {
			return true;
		}
		if (x < 0 || x == grid.length || y < 0 || y == grid[0].length || grid[x][y] != word.charAt(0)) {
			return false;
		}
		grid[x][y] ^= 256;
		boolean exist = helper(grid, word.substring(1), x - 1, y) || helper(grid, word.substring(1), x + 1, y)
				|| helper(grid, word.substring(1), x, y - 1) || helper(grid, word.substring(1), x, y + 1);
		grid[x][y] ^= 256;
		return exist;
	}
80. Remove Duplicates from Sorted Array II

Follow up for "Remove Duplicates":What if duplicates are allowed at most twice?Given sorted array nums = [1,1,1,2,2,3],Your function should return length = 5, with the first five elements of nums being 1122 and 3. It doesn't matter what you leave beyond the new length.

思路:直接赋值

	public int removeDuplicates(int[] nums) {
	    int id = 0;
	    for (int n : nums)
	        if (id < 2 || n > nums[id - 2])
	            nums[id++] = n;
	    return id;
	}
88. Merge Sorted Array
Given two sorted integer arrays  nums1  and  nums2 , merge  nums2  into  nums1  as one sorted array.(nums1 has enough space)
思路1:two pointers,每次交换完要重排
最优:从后往前,两个指针分别跟踪两数组
	public void merge(int[] nums1, int m, int[] nums2, int n) {
		int i = m - 1;
		int j = n - 1;
		int k = m + n - 1;
		while (i >= 0 && j >= 0) {
			if (nums1[i] > nums2[j]) {
				nums1[k--] = nums1[i--];
			} else {
				nums1[k--] = nums2[j--];
			}
		}
		while (j >= 0) {
			nums1[k--] = nums2[j--];
		}
	}
89. Gray Code
The gray code is a binary numeral system where two successive values differ in only one bit. Given a non-negative integer  n  representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.

For example, given n = 2, return [0,1,3,2]

思路1:发现了规律,n=1:0,1,n=2:0,1,3,2,n=3:0,1,3,2,6,7,5,4。第n个是第n-1个以倒序加2的n-1次方
思路2:更简洁,通过异或和右移
public List<Integer> grayCode(int n) {
		List<Integer> list = new ArrayList<Integer>();
		list.add(0);
		if(n == 0) return list;
		int number = (int)Math.pow(2,n);
		int i = 2;
		while(i <= number) {
			for(int j = list.size()- 1; j >= 0; j--) {
				list.add(list.get(j) + i / 2);
			}
			i *= 2;
		}
		return list;
	}
public List<Integer> grayCode(int n) {
	    List<Integer> result = new LinkedList<>();
	    for (int i = 0; i < 1<<n; i++) result.add(i ^ (i>>1));
	    return result;
	}
121. Best Time to Buy and Sell Stock

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

	public int maxProfit(int[] prices) {
		if (prices.length <= 1) {
			return 0;
		}
		int min = prices[0];
		int max = 0;
		for (int i = 1; i < prices.length; i++) {
			if (prices[i] < min) {
				min = prices[i];
			} else if (prices[i] - min > max) {
				max = prices[i] - min; 
			}
		}
		return max;
    }
122. Best Time to Buy and Sell Stock II

You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

区别上一题,可以买卖多次
思路,不要想太复杂了,只要出现今天比昨天多就进行买卖。

public int maxProfit(int[] prices) {
		int maxProfit = 0;
		for (int i = 1; i < prices.length; i++) {
			if (prices[i] > prices[i - 1]) {
				maxProfit += prices[i] - prices[i - 1];
			}
		}
		return maxProfit;
    }
123. Best Time to Buy and Sell Stock III

 Best Time to Buy and Sell Stock III(买股票,只可以进行两次)
 思路,找到卖出那一刻,前面是第一题模式,往后走又是第一题模式,错误在于,
 一定要保证在O(N),所以先存下来到某一个点前的利益,以及到某一个点往后的利益。

	public static int maxProfit(int[] prices) {
		/*
		 * 两个数组maxBefore和maxAfter,分别以i为中间点保存
		 */
		int maxProfit = 0;
		int length = prices.length;
		int min = Integer.MAX_VALUE;
		int res= 0;
		int[] maxBefore = new int[length];
		int[] maxAfter = new int[length];
		for(int i = 0; i < prices.length; i++){
			if(prices[i] < min){
				min = prices[i];
			} else if(prices[i] - min > res){
				res = prices[i] - min;
			}
			maxBefore[i] = res;
		}
		int max = 0;
		res = 0;
		for(int i = length - 1; i >= 0; i--) {
			if(max - prices[i] > res) {
				res = max - prices[i];
			} 
			if (prices[i] > max) {
				max = prices[i];
			}
			maxAfter[i] = res;
		}
		for(int i = 0 ; i < length; i++) {
			maxProfit = Math.max(maxProfit, maxBefore[i] + maxAfter[i]);
		}
		return maxProfit;
	}

309. Best Time to Buy and Sell Stock with Cooldown

股票问题:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

After you sell your stock, you cannot buy stock on next day.

这题是hard,意味着不看答案我也做不出来(= =)

discuss里解答超详细:https://discuss.leetcode.com/topic/30421/share-my-thinking-process

简要说就是动态规划,三个变量,buy,sell,rest

buy[I]是第I天买入,当前达到的最大利润

sell[I]第I天出售,达到的最大利润

rest[I]第I-1天出售,达到的最大利润

转化条件:

buy[i]  = max(rest[i-1]-price, buy[i-1]) 
sell[i] = max(buy[i-1]+price, sell[i-1])
rest[i] = max(sell[i-1], buy[i-1], rest[i-1])

 buy[i] <= rest[i] which means rest[i] = max(sell[i-1], rest[i-1]). That made sure [buy, rest, buy] is never occurred.

A further observation is that and rest[i] <= sell[i] is also true therefore

rest[i] = sell[i-1]

Substitute this in to buy[i] we now have 2 functions instead of 3:

buy[i] = max(sell[i-2]-price, buy[i-1])
sell[i] = max(buy[i-1]+price, sell[i-1])
public int maxProfit(int[] prices) {
    int sell = 0, prev_sell = 0, buy = Integer.MIN_VALUE, prev_buy;
    for (int price : prices) {
        prev_buy = buy;
        buy = Math.max(prev_sell - price, prev_buy);
        prev_sell = sell;
        sell = Math.max(prev_buy + price, prev_sell);
    }
    return sell;
}

136. Single Number

Given an array of integers, every element appears twice except for one. Find that single one

	public int singleNumber(int[] nums) {
        if (nums ==null){
            return 0;
        }
        if (nums.length == 1) {
                return nums[0];
        }
		int re = 0;
		for (int i = 0; i < nums.length; i++) {
			re ^= nums[i];
		}
		return re;
    }

152. Maximum Product Subarray

子串乘积最大的子串长度

For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.

两个思路:

1.当前状态的最大值,要么是上一个状态的最大值乘以当前值(当前值为正),要么是上一个最小值乘以当前值(负),要么为0。o(n)

public static int maxProduct(int[] a, int n) {
		int max = a[0];
		int min = a[0];
		int A = max;
		for (int i = 1; i < a.length; i++) {
			int tmpMax = max * a[i];
			int tmpMin = min * a[i];
			max = Math.max(Math.max(tmpMax, tmpMin), a[i]);
			min = Math.min(Math.min(tmpMax, tmpMin), a[i]);
			A = Math.max(max, A);
		}
		return A;
	}

179. Largest Number

Given a list of non negative integers, arrange them such that they form the largest number.

For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330.

Note: The result may be very large, so you need to return a string instead of an integer.

思路:45,4比较应该45放前面,12和121应该12放前面,所以不是谁大谁就在前面。正确应该是a+b和b+a的最大值(下面是leetcode里discuss大神的代码)
public String largestNumber(int[] nums) {
		if(nums == null || nums.length == 0)
		    return "";
		// Convert int array to String array, so we can sort later on
		String[] s_num = new String[nums.length];
		for(int i = 0; i < nums.length; i++) {
			s_num[i] = String.valueOf(nums[i]);
		}
		// Comparator to decide which string should come first in concatenation
		Comparator<String> comp = new Comparator<String>(){
			@Override
			public int compare(String str1, String str2){
				String s1 = str1 + str2;
				String s2 = str2 + str1;
				return s2.compareTo(s1); // reverse order here, so we can do append() later
			}
		};
		Arrays.sort(s_num, comp);
		// An extreme edge case by lc, say you have only a bunch of 0 in your int array
		if(s_num[0].charAt(0) == '0')
			return "0";
		StringBuilder sb = new StringBuilder();
		for(String s: s_num) {
			sb.append(s);
		}
		return sb.toString();
    }

410. Split Array Largest Sum

给一个数组,将其分成n部分,使其每部分的和尽可能的接近(题目中给出的条件是,使其中和最大的一组数,和最小)。

比如:

Input:
nums = [7,2,5,10,8]
m = 2

Output:
18

分为:【7,2,5】【10,8】

和上一题类似,隐藏的比较深一点,其实也是一个背包问题,只不过是二维费用问题,即隐藏了一个背包放置数量为n/2个

另一个很厉害的思路:用二分法。结果值在数组最大值和数组和之间,因此l为max,r为sum,然后确定这个数组是否可以被分成大于m个数组,若可以,则说明这个数选小了:l = mid + 1,如果不可,r = mid - 1

public int splitArray(int[] nums, int m) {
        int max = 0; long sum = 0;
        for (int num : nums) {
            max = Math.max(num, max);
            sum += num;
        }
        if (m == 1) return (int)sum;
        //binary search
        long l = max; long r = sum;
        while (l <= r) {
            long mid = (l + r)/ 2;
            if (valid(mid, nums, m)) {
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        return (int)l;
    }
    public boolean valid(long target, int[] nums, int m) {
        int count = 1;
        long total = 0;
        for(int num : nums) {
            total += num;
            if (total > target) {
                total = num;
                count++;
                if (count > m) {
                    return false;
                }
            }
        }
        return true;
    }





HashTable

36. Valid Sudoku

(partially filled)

最优思路:每一个board[i][j]都要加入三次set

  public boolean isValidSudoku(char[][] board) {
		Set<String> set = new HashSet<String>();
		for(int i = 0; i < 9; i++) {
			for(int j = 0; j < 9; j++) { 
				if(board[i][j] != '.') {
					if(!set.add(board[i][j] + " in row" + i) ||
							!set.add(board[i][j] + " in column" + j) ||
							!set.add(board[i][j] + " in block" + i/3 + " " + j/3))
						return false;
				}
			}
		}
		return true;
	}

37. Sudoku Solver           
填满sudoku(hard)

思路:若当前空可填,则填且继续填下一个。若不可,重置当前点,继续遍历char。完全遍历结束找不到,返回false

 public void solveSudoku(char[][] board) {
        if(board == null || board.length == 0)
            return;
        solve(board);
    }
	public boolean solve(char[][] board) {
		for(int i = 0; i < 9; i++) {
			for(int j = 0; j < 9; j++) {
				if(board[i][j] == '.') {
					for(char c = '1'; c <= '9'; c++) {
						if(put(board, i ,j, c))  {
							board[i][j] = c;
							if(solve(board))
                                return true; 
                            else
                                board[i][j] = '.';
						}
					}
					return false;
				}
			}
		}
		return true;
    }
	public boolean put(char[][] board, int x, int y, char c) {
		for(int i = 0; i < 9; i++) {
			if(board[x][i] == c) return false;
			if(board[i][y] == c) return false;
			if(board[3 * (x / 3) + i / 3][3 * (y / 3) + i % 3] == c) return false;
 		}
		return true;
	}

49. Group Anagrams
求字母相同的所有重排组合

example,given: ["eat", "tea", "tan", "ate", "nat", "bat"], Return:

[
  ["ate", "eat","tea"],
  ["nat","tan"],
  ["bat"]
]

public List<List<String>> groupAnagrams(String[] strs) {
		Map<String, List<String>> map = new HashMap<String, List<String>>();
		for (int i = 0; i < strs.length; i++) {
			char[] c = strs[i].toCharArray();
			Arrays.sort(c);
			String s = String.valueOf(c);
			if (!map.containsKey(s)) {
				map.put(s, new ArrayList<String>());
			}
			map.get(s).add(strs[i]);
		}
		List<List<String>> re = new ArrayList<List<String>>(map.values());
		return re;
	}

 
 
 
 
 
 
74. Search a 2D Matrix

二维数组依次递增(行内,行末尾和下一行开头),查询某数

思路:我的想法是二分法找到行,再二分找行内数。最优:既然依次增大, 将二维数组看成一维就可以了

	public boolean searchMatrix2(int[][] matrix, int target) {
		if (matrix.length < 1 || matrix[0].length < 1) {
			return false;
		}
		int n = matrix.length;
		int m = matrix[0].length;
		int l = 0, h = m * n - 1;
		while (l <= h) {
			int mid = (l + h) / 2;
			if (matrix[mid / m][mid % m] < target) {
				l = mid + 1;
			} else if (matrix[mid / m][mid % m] > target){
				h = mid - 1;
			} else {
				return true;
			}
		}
		return false;
	}

Tree

101 二叉树是否对称
[html]  view plain  copy
  1. public boolean isSymmetric(TreeNode root) {  
  2.         if (root == null) {  
  3.             return true;  
  4.         }  
  5.           
  6.         return isTwoSymmetric(root.left, root.right);  
  7.     }  
  8.     public static boolean isTwoSymmetric(TreeNode l, TreeNode r) {  
  9.         if (l == null || r == null) {  
  10.             if (l == null && r == null) {  
  11.                 return true;  
  12.             }  
  13.             return false;  
  14.         }  
  15.         if (l.val != r.val) {  
  16.             return false;  
  17.         }  
  18.         if (!isTwoSymmetric(l.left, r.right) || !isTwoSymmetric(l.right, r.left)) {  
  19.             return false;  
  20.         }  
  21.         return true;  
  22.     }  
102 二叉树的层次遍历

 * res.add(new ArrayList<Integer>(2));不对  * 思路:用一个count保存该层共有几个,poll出该层的个数即可

[html]  view plain  copy
  1. public List<List<Integer>> levelOrder(TreeNode root) {  
  2.     List<List<Integer>> res = new ArrayList<List<Integer>>();  
  3.     if (root == null) {  
  4.         return res;  
  5.     }  
  6.        Queue<TreeNode> queue = new ArrayDeque<TreeNode>();  
  7.        queue.add(root);  
  8.        List<Integer> l = new ArrayList<Integer>();  
  9.        while (!queue.isEmpty()) {  
  10.         int count = queue.size();  
  11.         TreeNode tmp;  
  12.         for (int i = 0; i < count; i++) {  
  13.             tmp = queue.poll();  
  14.             if (tmp.left != null)  
  15.                 queue.add(tmp.left);  
  16.             if (tmp.right != null)  
  17.                 queue.add(tmp.right);   
  18.             l.add(tmp.val);  
  19.         }  
  20.         res.add(l);  
  21.         l = new ArrayList<Integer>();  
  22.        }          
  23.        return res;  
  24.    }  
103. Binary Tree Zigzag Level Order Traversal

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).根节点为从左至右

思路:1 中序; 2 递归,每层level + 1,判断其奇偶,决定是否将某点插入到list开头

[html]  view plain  copy
  1. public List<List<Integer>> zigzagLevelOrder(TreeNode root) {  
  2.         List<List<Integer>> res = new ArrayList<List<Integer>>();  
  3.         if (root == null) {  
  4.             return res;  
  5.         }  
  6.         Queue<TreeNode> queue = new ArrayDeque<TreeNode>();  
  7.         queue.add(root);  
  8.         boolean fromLeft = true; // 是否从左开始  
  9.         while (!queue.isEmpty()) {  
  10.             List<Integer> list = new ArrayList<Integer>();  
  11.             int cnt = queue.size();  
  12.             while (cnt-- > 0) {  
  13.                 TreeNode x = queue.poll();  
  14.                 list.add(x.val);  
  15.                 if (x.left != null) {  
  16.                     queue.add(x.left);  
  17.                 }  
  18.                 if (x.right != null) {  
  19.                     queue.add(x.right);  
  20.                 }  
  21.             }  
  22.             if (!fromLeft) {  
  23.                 Collections.reverse(list);  
  24.             }  
  25.             fromLeft = fromLeft ? false : true;  
  26.             res.add(list);  
  27.         }  
  28.         return res;  
  29.     }  

[html]  view plain  copy
  1. /*  
  2.      * 最优  
  3.      */  
  4.     public List<List<Integer>> zigzagLevelOrder2(TreeNode root)   
  5.     {  
  6.         List<List<Integer>> sol = new ArrayList<>();  
  7.         travel(root, sol, 0);  
  8.         return sol;  
  9.     }  
  10.       
  11.     private void travel(TreeNode curr, List<List<Integer>> sol, int level)  
  12.     {  
  13.         if(curr == null) return;  
  14.           
  15.         if(sol.size() <= level)  
  16.         {  
  17.             List<Integer> newLevel = new LinkedList<>();  
  18.             sol.add(newLevel);  
  19.         }  
  20.           
  21.         List<Integer> collection  = sol.get(level);  
  22.         if(level % 2 == 0) collection.add(curr.val);  
  23.         else collection.add(0, curr.val);  
  24.           
  25.         travel(curr.left, sol, level + 1);  
  26.         travel(curr.right, sol, level + 1);  
  27.     }  

107. Binary Tree Level Order Traversal II

从底向上的层遍历。还是中序(bfs),也可以dfs

[html]  view plain  copy
  1. public List<List<Integer>> levelOrderBottom(TreeNode root) {  
  2.         List<List<Integer>> res = new ArrayList<List<Integer>>();  
  3.         if (root == null) {  
  4.             return res;  
  5.         }  
  6.         Queue<TreeNode> queue = new ArrayDeque<TreeNode>();  
  7.         queue.offer(root);  
  8.         while (!queue.isEmpty()) {  
  9.             List<Integer> list = new ArrayList<Integer>();  
  10.             int cnt = queue.size();  
  11.             while (cnt-- > 0) {  
  12.                 TreeNode x = queue.poll();  
  13.                 list.add(x.val);  
  14.                 if (x.left != null) {  
  15.                     queue.offer(x.left);  
  16.                 }  
  17.                 if (x.right != null) {  
  18.                     queue.offer(x.right);  
  19.                 }  
  20.             }  
  21.             res.add(0, list);  
  22.         }  
  23.         return res;  
  24.     }  
[html]  view plain  copy
  1. public List<List<Integer>> levelOrderBottom(TreeNode root) {  
  2.             List<List<Integer>> wrapList = new LinkedList<List<Integer>>();  
  3.             levelMaker(wrapList, root, 0);  
  4.             return wrapList;  
  5.         }  
  6.           
  7.         public void levelMaker(List<List<Integer>> list, TreeNode root, int level) {  
  8.             if(root == null) return;  
  9.             if(level >= list.size()) {  
  10.                 list.add(0, new LinkedList<Integer>());  
  11.             }  
  12.             levelMaker(list, root.left, level+1);  
  13.             levelMaker(list, root.right, level+1);  
  14.             list.get(list.size()-level-1).add(root.val);  
  15.         }  

108. Convert Sorted Array to Binary Search Tree
递增数组转为height balanced BST
[html]  view plain  copy
  1. public TreeNode sortedArrayToBST(int[] nums) {  
  2.     TreeNode root = null;  
  3.     if (nums.length == 0) {  
  4.         return root;  
  5.     }  
  6.     root = helper(nums, 0, nums.length - 1);  
  7.     return root;  
  8.    }  
  9. public TreeNode helper(int[] nums, int b, int e) {  
  10.     if (b > e) {  
  11.         return null;  
  12.     }  
  13.     int index = (e + b) / 2; // 注意这里  
  14.     TreeNode root = new TreeNode(nums[index]);  
  15.     root.left = helper(nums, b, index - 1);  
  16.     root.right = helper(nums, index + 1, e);  
  17.     return root;  
  18. }  
109. Convert Sorted List to Binary Search Tree
同上,不过是从List转换

思路:两个指针,fast速度为slow的两倍。slow即为root

[html]  view plain  copy
  1. public TreeNode sortedListToBST(ListNode head) {  
  2.     if(head==null) return null;  
  3.     return toBST(head,null);  
  4. }  
  5. public TreeNode toBST(ListNode head, ListNode tail){  
  6.     ListNode slow = head;  
  7.     ListNode fast = head;  
  8.     if(head==tail) return null;  
  9.       
  10.     while(fast!=tail&&fast.next!=tail){  
  11.         fast = fast.next.next;  
  12.         slow = slow.next;  
  13.     }  
  14.     TreeNode thead = new TreeNode(slow.val);  
  15.     thead.left = toBST(head,slow);  
  16.     thead.right = toBST(slow.next,tail);  
  17.     return thead;  
  18. }  

另外一种in-place(o(1) space, o(n) time)

private ListNode node;

public TreeNode sortedListToBST(ListNode head) {
	if(head == null){
		return null;
	}
	
	int size = 0;
	ListNode runner = head;
	node = head;
	
	while(runner != null){
		runner = runner.next;
		size ++;
	}
	
	return inorderHelper(0, size - 1);
}

public TreeNode inorderHelper(int start, int end){
	if(start > end){
		return null;
	}
	
	int mid = start + (end - start) / 2;
	TreeNode left = inorderHelper(start, mid - 1);
	
	TreeNode treenode = new TreeNode(node.val);
	treenode.left = left;
	node = node.next;

	TreeNode right = inorderHelper(mid + 1, end);
	treenode.right = right;
	
	return treenode;
}



104. Maximum Depth of Binary Tree
[html]  view plain  copy
  1. public int maxDepth(TreeNode root) {  
  2.         if(root == null) {  
  3.             return 0;  
  4.         }  
  5.         int left = maxDepth(root.left);  
  6.         int right = maxDepth(root.right);  
  7.         return Math.max(left, right) + 1;  
  8.     }   

[html]  view plain  copy
  1. public int maxDepth(TreeNode root) {  
  2.         if(root==null){  
  3.             return 0;  
  4.         }  
  5.         return 1+Math.max(maxDepth(root.left),maxDepth(root.right));  
  6.     }  

111. Minimum Depth of Binary Tree
 二叉树的最小深度,注意一定是左右子节点都为空才算叶子节点

[html]  view plain  copy
  1. public int minDepth2(TreeNode root) {  
  2.         if(root == null) {  
  3.             return 0;  
  4.         }  
  5.         int left = minDepth2(root.left);  
  6.         int right = minDepth2(root.right);  
  7.         return (left == 0 || right == 0) ? left + right + 1: Math.min(left,right) + 1;  
  8.     }  

105. Construct Binary Tree from Preorder and Inorder Traversal

根据前中序推出树

思路:Preorder traversing implies that PRE[0] is the root node.
Then we can find this PRE[0] in IN, say it's IN[5].
Now we know that IN[5] is root, so we know that IN[0] - IN[4] is on the left side, IN[6] to the end is on the right side.
Recursively doing this on subarrays, we can build a tree out of it :)

pre:32154

in:21345

树:

     3

2       5

   1 4

[html]  view plain  copy
  1. public TreeNode buildTree(int[] preorder, int[] inorder) {  
  2.     return helper(0, 0, inorder.length - 1, preorder, inorder);  
  3. }  
  4.   
  5. public TreeNode helper(int preStart, int inStart, int inEnd, int[] preorder, int[] inorder) {  
  6.     if (preStart > preorder.length - 1 || inStart > inEnd) {  
  7.         return null;  
  8.     }  
  9.     TreeNode root = new TreeNode(preorder[preStart]);  
  10.     int inIndex = 0; // Index of current root in inorder  
  11.     for (int i = inStart; i <= inEnd; i++) {  
  12.         if (inorder[i] == root.val) {  
  13.             inIndex = i;  
  14.         }  
  15.     }  
  16.     root.left = helper(preStart + 1, inStart, inIndex - 1, preorder, inorder);  
  17.     root.right = helper(preStart + inIndex - inStart + 1, inIndex + 1, inEnd, preorder, inorder);  
  18.     return root;  
  19. }  

106. Construct Binary Tree from Inorder and Postorder Traversal
后:12453

[html]  view plain  copy
  1. public TreeNode buildTree(int[] inorder, int[] postorder) {  
  2.     if (inorder == null || postorder == null || inorder.length != postorder.length)  
  3.         return null;  
  4.     HashMap<Integer, Integer> hm = new HashMap<Integer,Integer>();  
  5.     for (int i=0;i<inorder.length;++i)  
  6.         hm.put(inorder[i], i);  
  7.     return buildTreePostIn(inorder, 0, inorder.length-1, postorder, 0,   
  8.                           postorder.length-1,hm);  
  9. }  
  10.   
  11. private TreeNode buildTreePostIn(int[] inorder, int is, int ie, int[] postorder, int ps, int pe,   
  12.                                  HashMap<Integer,Integer> hm){  
  13.     if (ps>pe || is>ie) return null;  
  14.     TreeNode root = new TreeNode(postorder[pe]);  
  15.     int ri = hm.get(postorder[pe]);  
  16.     root.left = buildTreePostIn(inorder, is, ri-1, postorder, ps, ps+ri-is-1, hm); // 这里注意root左边一共有ri-is个,若ps为0,则为0,1,即至2-1为止  
  17.     root.right = buildTreePostIn(inorder,ri+1, ie, postorder, ps+ri-is, pe-1, hm);  
  18.     return root;  
  19. }  

110. Balanced Binary Tree

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.

[html]  view plain  copy
  1. public class Solution {  
  2.     public boolean isBalanced(TreeNode root) {  
  3.     if(root==null)  
  4.         return true;  
  5.     Boolean leftResult=isBalanced(root.left);  
  6.     Boolean rightResult=isBalanced(root.right);  
  7.     return Math.abs(Depth(root.left)-Depth(root.right))<=1&&leftResult&&rightResult;  
  8.     }  
  9.     public int Depth(TreeNode root){  
  10.         if(root==null)  
  11.         return 0;  
  12.         int left=Depth(root.left);  
  13.         int right=Depth(root.right);  
  14.         return Math.max(left,right)+1;  
  15.     }  
  16. }  
112. Path Sum

题目:判断root到叶结点的每条路中是否加起来等于sum * 思路:输入为null返回false, * 未bug-free:不能cur > num就返回false,因为可能会有负数

For example:
Given the below binary tree and sum = 22,
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1

return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

[html]  view plain  copy
  1. public boolean hasPathSum2(TreeNode root, int sum) {  
  2.         if(root == null) return false;  
  3.         if(root.left == null && root.right == null && sum - root.val == 0) return true;  
  4.         return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);  
  5.     }  
113. Path Sum II

Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.

For example:
Given the below binary tree and sum = 22,
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1

return

[
   [5,4,11,2],
   [5,8,4,5]
]

[html]  view plain  copy
  1. public List<List<Integer>> pathSum(TreeNode root, int sum){  
  2.         List<List<Integer>> result  = new LinkedList<List<Integer>>();  
  3.         List<Integer> currentResult  = new LinkedList<Integer>();  
  4.         pathSum(root,sum,currentResult,result);  
  5.         return result;  
  6.     }  
  7.     public void pathSum(TreeNode root, int sum, List<Integer> currentResult,  
  8.             List<List<Integer>> result) {  
  9.   
  10.         if (root == null)  
  11.             return;  
  12.         currentResult.add(new Integer(root.val));  
  13.         if (root.left == null && root.right == null && sum == root.val) {  
  14.             result.add(new LinkedList(currentResult));  
  15.             currentResult.remove(currentResult.size() - 1);//don't forget to remove the last integer  
  16.             return;  
  17.         } else {  
  18.             pathSum(root.left, sum - root.val, currentResult, result);  
  19.             pathSum(root.right, sum - root.val, currentResult, result);  
  20.         }  
  21.         currentResult.remove(currentResult.size() - 1);  
  22.     }  
[html]  view plain  copy
  1. public List<List<Integer>> pathSum(TreeNode root, int sum) {
  2.       List<List<Integer>> res = new ArrayList<List<Integer>>();  
  3.         dfs(res, new ArrayList<Integer>(), root, 0, sum);  
  4.         return res;  
  5.     }  
  6.     public void dfs (List<List<Integer>> res, List<Integer> list, TreeNode root, int sum, int target) {  
  7.         if (root == null) {  
  8.             return;  
  9.         }  
  10.         list.add(root.val);  
  11.         sum += root.val;  
  12.         if (root.left == null && root.right == null && sum == target) {  
  13.             res.add(new ArrayList<Integer>(list));  
  14.             list.remove(list.get(list.size() - 1)); // 保证叶节点被删除  
  15.             return;  
  16.         }  
  17.         dfs(res, list, root.left, sum, target);  
  18.         dfs(res, list, root.right, sum, target);  
  19.         list.remove(list.get(list.size() - 1)); // root的左右节点均遍历完且删掉,去掉root点  
  20.     }
235. Lowest Common Ancestor of a Binary Search Tree
 

/**
	 * 特指 Binary Search Tree
	 * 从root开始,只要p和q都是root的同一子树,就往下走(意思是他们的values都比root的小或大)
	 */
	public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
		if (root == null) {
			return null;
		}
        while((root.val - p.val) * (root.val - q.val) > 0) {
        	 root = p.val < root.val ? root.left : root.right;
        }
        return root;
    }
	/*
	 * 另外一种容易想的
	 */
	public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
	        if(root.val > p.val && root.val > q.val){
	            return lowestCommonAncestor(root.left, p, q);
	        }else if(root.val < p.val && root.val < q.val){
	            return lowestCommonAncestor(root.right, p, q);
	        }else{
	            return root;
	        }
	  }

236. Lowest Common Ancestor of a Binary Tree
不是二叉查找树,递归

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
	    if (root == null || root == p || root == q) return root;
	    TreeNode left = lowestCommonAncestor(root.left, p, q);
	    TreeNode right = lowestCommonAncestor(root.right, p, q);
	    if (left != null && right != null)   {
	    	return root;
	    }
	    return left != null ? left : right;
	}

208. Implement Trie (Prefix Tree)
Implement a trie with insertsearch, and startsWith methods.
思路:TrieNode中不需要存储val,直接用数组位置表示字符即可
class TrieNode {
    public boolean isWord; 
    public TrieNode[] children = new TrieNode[26];
    public TrieNode() {}
}

public class Trie {
    private TrieNode root;
    public Trie() {
        root = new TrieNode();
    }
    /** Inserts a word into the trie. */
    public void insert(String word) {
        TrieNode ws = root;
        for(int i = 0; i < word.length(); i++){
            char c = word.charAt(i);
            if(ws.children[c - 'a'] == null){
                ws.children[c - 'a'] = new TrieNode();
            }
            ws = ws.children[c - 'a'];
        }
        ws.isWord = true;
    }
    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        TrieNode ws = root; 
        for(int i = 0; i < word.length(); i++){
            char c = word.charAt(i);
            if(ws.children[c - 'a'] == null) return false;
            ws = ws.children[c - 'a'];
        }
        return ws.isWord;
    }
    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        TrieNode ws = root; 
        for(int i = 0; i < prefix.length(); i++) {
            char c = prefix.charAt(i);
            if(ws.children[c - 'a'] == null) return false;
            ws = ws.children[c - 'a'];
        }
        return true;
    }
}


非递归的方式中序遍历

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> list = new ArrayList<Integer>();

    Stack<TreeNode> stack = new Stack<TreeNode>();
    TreeNode cur = root;

    while(cur!=null || !stack.empty()){
        while(cur!=null){
            stack.add(cur);
            cur = cur.left;
        }
        cur = stack.pop();
        list.add(cur.val);
        cur = cur.right;
    }

    return list;
}
114. Flatten Binary Tree to Linked List

将一个二叉树变为中序链表

思路:后序遍历二叉树,依次在前面加节点

Given

         1
        / \
       2   5
      / \   \
     3   4   6

The flattened tree should look like:

   1
    \
     2
      \
       3
        \
         4
          \
           5
            \
             6
public void flatten(TreeNode root) {
	    if (root == null)
	        return;
	    flatten(root.right);
	    flatten(root.left);
	    root.right = prev;
	    root.left = null;
	    prev = root;
	}


230. Kth Smallest Element in a BST

二叉搜索树的第k个元素

注意二叉搜索树不一定完全,所以不能用(l+r) / 2计算根节点

最优:


Recursive:
	int count = 0;
    	int result = Integer.MIN_VALUE;

    	public int kthSmallest(TreeNode root, int k) {
    	    traverse(root, k);
    	    return result;
    	}
    	public void traverse(TreeNode root, int k) {
    	    if(root == null) return;
    	    traverse(root.left, k);
    	    count ++;
    	    if(count == k) {
    	    	result = root.val;
    	    	return;
    	    }
    	    traverse(root.right, k);       
    	}
相同思路:
Iterative:

 public int kthSmallest(TreeNode root, int k) {
     Stack<TreeNode> stack = new Stack<TreeNode>();
     TreeNode p = root;
     int count = 0;
     
     while(!stack.isEmpty() || p != null) {
         if(p != null) {
             stack.push(p);  // Just like recursion
             p = p.left;   
             
         } else {
            TreeNode node = stack.pop();
            if(++count == k) return node.val; 
            p = node.right;
         }
     }
     
     return Integer.MIN_VALUE;
 }
最优2,先计算左子树的节点数public int kthSmallest(TreeNode root, int k) {
        int count = countNodes(root.left);
        if (k <= count) {
            return kthSmallest(root.left, k);
        } else if (k > count + 1) {
            return kthSmallest(root.right, k-1-count); // 1 is counted as current node
        }  
        return root.val;
    }
    
    public int countNodes(TreeNode n) {
        if (n == null) return 0;
        
        return 1 + countNodes(n.left) + countNodes(n.right);
    }

若可以更改树的定义:(稍麻烦一点)
public class Solution {
        public int kthSmallest(TreeNode root, int k) {
            TreeNodeWithCount rootWithCount = buildTreeWithCount(root);
            return kthSmallest(rootWithCount, k);
        }
        
        private TreeNodeWithCount buildTreeWithCount(TreeNode root) {
            if (root == null) return null;
            TreeNodeWithCount rootWithCount = new TreeNodeWithCount(root.val);
            rootWithCount.left = buildTreeWithCount(root.left);
            rootWithCount.right = buildTreeWithCount(root.right);
            if (rootWithCount.left != null) rootWithCount.count += rootWithCount.left.count;
            if (rootWithCount.right != null) rootWithCount.count += rootWithCount.right.count;
            return rootWithCount;
        }
        
        private int kthSmallest(TreeNodeWithCount rootWithCount, int k) {
            if (k <= 0 || k > rootWithCount.count) return -1;
            if (rootWithCount.left != null) {
                if (rootWithCount.left.count >= k) return kthSmallest(rootWithCount.left, k);
                if (rootWithCount.left.count == k-1) return rootWithCount.val;
                return kthSmallest(rootWithCount.right, k-1-rootWithCount.left.count);
            } else {
                if (k == 1) return rootWithCount.val;
                return kthSmallest(rootWithCount.right, k-1);
            }
        }
        
        class TreeNodeWithCount {
            int val;
            int count;
            TreeNodeWithCount left;
            TreeNodeWithCount right;
            TreeNodeWithCount(int x) {val = x; count = 1;};
        }
    }

96. Unique Binary Search Trees

Given n, how many structurally unique BST's (binary search trees) that store values 1...n?

For example,
Given n = 3, there are a total of 5 unique BST's.

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

思路:dp,dp[1] = 1 ,dp[2] =2 ,dp[3] = 5, dp[4] =14 ,怎么得到dp[5]呢
对于每一个root node,需要知道有多少种左子树,多少种右子树
First we pick 1 as root, for the left sub tree, there are none; for the right sub tree, we need count how many possible trees are there constructed from {2,3,4,5}, apparently it's the same number as {1,2,3,4}. So the total number of trees under "1" picked as root is dp[0] * dp[4] = 14. (assume dp[0] =1). Similarly, root 2 has dp[1]*dp[3] = 5 trees. root 3 has dp[2]*dp[2] = 4, root 4 has dp[3]*dp[1]= 5 and root 5 has dp[0]*dp[4] = 14. Finally sum the up and it's done.
 public int numTrees(int n) {
    int [] dp = new int[n+1];
    dp[0]= 1;
    dp[1] = 1;
    for(int level = 2; level <=n; level++)
        for(int root = 1; root<=level; root++)
            dp[level] += dp[level-root]*dp[root-1];
    return dp[n];
}

199. Binary Tree Right Side View


Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

For example:
Given the following binary tree,

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

You should return [1, 3, 4].

思路1:按行打印
思路2: 1.Each depth of the tree only select one node. View depth is current size of result list.
public List<Integer> rightSideView(TreeNode root) {
        Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
        
        List<Integer> list = new ArrayList<Integer>();
        if (root == null) {
        	return list;
        }
        queue.add(root);
        while (!queue.isEmpty()) {
        	int size = queue.size();
        	TreeNode t = null;
        	while (size >= 1) {
        		t = queue.poll();
        		if (t.left != null) {
        		  queue.add(t.left);   
        		}
        		if (t.right != null) {
        		  queue.add(t.right);   
        		}
        		size--;
        	}
        	list.add(t.val);
        	
        }
        return list;
    }

public class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> result = new ArrayList<Integer>();
        rightView(root, result, 0);
        return result;
    }
    
    public void rightView(TreeNode curr, List<Integer> result, int currDepth){
        if(curr == null){
            return;
        }
        if(currDepth == result.size()){
            result.add(curr.val);
        }
        
        rightView(curr.right, result, currDepth + 1);
        rightView(curr.left, result, currDepth + 1);
        
    }
}





bfs/union find


130. Surrounded Regions

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.(把x包围的替换为X)

X X X X
X O O X
X X O X
X O X X

After running your function, the board should be:

X X X X
X X X X
X X X X
X O X X

思路1:

参考:http://www.cnblogs.com/springfor/p/3869853.html

这道题是说一个O周围都是X那么这个O就得变成X。那么就可以发现四周这一圈如果有O肯定不能四周都被X包围,同时这个O也将会是潜在的内部的O的缺口,
让内部的O不能都被X覆盖。因此,思路就是先对四周的O进行特殊处理,用BFS走,把所有这个O连接的O(包括这个O)都涂成B。这样子,对于原来的棋盘来说,
没有变成#的O就是四周没有被O污染的,四周都是X,那么对其变成X。而所有#就是那些原来是O但是不是四周都被X包围的,把它们再还原成O。

思路2:可以利用并查集。如果是为O的在外围,和dummy node相union,每个O都和其四周四个点union。最后遍历所有点,只要和dummy node相连,就不能置为X

class Point {
int x;
int y;
Point(int x, int y) {
	this.x = x;
	this.y = y;
}
}
public class Main3 {
	public static void main(String[] args) {
		
	}
	public static void solve(char[][] board) {
		if (board == null || board.length == 0)
			return;
		int rows = board.length, columns = board[0].length;
		int[][] direction = { { -1, 0 }, { 1, 0 }, { 0, 1 }, { 0, -1 } };
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < columns; j++) {
				if ((i == 0 || i == rows - 1 || j == 0 || j == columns - 1) && board[i][j] == 'O') {
					Queue<Point> queue = new LinkedList<Point>();
					board[i][j] = 'B';
					queue.offer(new Point(i, j));
					while (!queue.isEmpty()) {
						Point point = queue.poll();
						for (int k = 0; k < 4; k++) {
							int x = direction[k][0] + point.x;
							int y = direction[k][1] + point.y;
							if (x >= 0 && x < rows && y >= 0 && y < columns && board[x][y] == 'O') {
								board[x][y] = 'B';
								queue.offer(new Point(x, y));
							}
						}
					}
				}
			}
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < columns; j++) {
				if (board[i][j] == 'B')
					board[i][j] = 'O';
				else if (board[i][j] == 'O')
					board[i][j] = 'X';
			}

	}
}

方法2:并查集

public class Solution {
    int rows, cols;
    
    public void solve(char[][] board) {
        if(board == null || board.length == 0) return;
        
        rows = board.length;
        cols = board[0].length;
        
        // last one is dummy, all outer O are connected to this dummy
        UnionFind uf = new UnionFind(rows * cols + 1);
        int dummyNode = rows * cols;
        
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < cols; j++) {
                if(board[i][j] == 'O') {
                    if(i == 0 || i == rows-1 || j == 0 || j == cols-1) {
                        uf.union(node(i,j), dummyNode);
                    }
                    else {
                        if(i > 0 && board[i-1][j] == 'O')  uf.union(node(i,j), node(i-1,j));
                        if(i < rows-1 && board[i+1][j] == 'O')  uf.union(node(i,j), node(i+1,j));
                        if(j > 0 && board[i][j-1] == 'O')  uf.union(node(i,j), node(i, j-1));
                        if(j < cols-1 && board[i][j+1] == 'O')  uf.union(node(i,j), node(i, j+1));
                    }
                }
            }
        }
        
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < cols; j++) {
                if(uf.isConnected(node(i,j), dummyNode)) {
                    board[i][j] = 'O';
                }
                else {
                    board[i][j] = 'X';
                }
            }
        }
    }
    
    int node(int i, int j) {
        return i * cols + j;
    }
}

class UnionFind {
    int [] parents;
    public UnionFind(int totalNodes) {
        parents = new int[totalNodes];
        for(int i = 0; i < totalNodes; i++) {
            parents[i] = i;
        }
    }
    
    void union(int node1, int node2) {
        int root1 = find(node1);
        int root2 = find(node2);
        if(root1 != root2) {
            parents[root2] = root1;
        }
    }
    
    int find(int node) {
        while(parents[node] != node) {
            parents[node] = parents[parents[node]];
            node = parents[node];
        }
        
        return node;
    }
    
    boolean isConnected(int node1, int node2) {
        return find(node1) == find(node2);
    }
}













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
### 回答1: 好的,我来用中文回复这个链接:https://leetcode-cn.com/tag/dynamic-programming/ 这个链接是 LeetCode 上关于动态规划的题目集合。动态规划是一种常用的算法思想,可以用来解决很多实际问题,比如最长公共子序列、背包问题、最短路径等等。在 LeetCode 上,动态规划也是一个非常重要的题型,很多题目都需要用到动态规划的思想来解决。 这个链接里包含了很多关于动态规划的题目,按照难度从简单到困难排列。每个题目都有详细的题目描述、输入输出样例、题目解析和代码实现等内容,非常适合想要学习动态规划算法的人来练习和提高自己的能力。 总之,这个链接是一个非常好的学习动态规划算法的资源,建议大家多多利用。 ### 回答2: 动态规划是一种算法思想,通常用于优化具有重叠子问题和最优子结构性质的问题。由于其成熟的数学理论和强大的实用效果,动态规划在计算机科学、数学、经济学、管理学等领域均有重要应用。 在计算机科学领域,动态规划常用于解决最优化问题,如背包问题、图像处理、语音识别、自然语言处理等。同时,在计算机网络和分布式系统中,动态规划也广泛应用于各种优化算法中,如链路优化、路由算法、网络流量控制等。 对于算法领域的程序员而言,动态规划是一种必要的技能和知识点。在LeetCode这样的程序员平台上,题目分类和标签设置十分细致和方便,方便程序员查找并深入学习不同类型的算法。 LeetCode的动态规划标签下的题目涵盖了各种难度级别和场景的问题。从简单的斐波那契数列、迷宫问题到可以用于实际应用的背包问题、最长公共子序列等,难度不断递进且话题丰富,有助于开发人员掌握动态规划的实际应用技能和抽象思维模式。 因此,深入LeetCode动态规划分类下的题目学习和练习,对于程序员的职业发展和技能提升有着重要的意义。 ### 回答3: 动态规划是一种常见的算法思想,它通过将问题拆分成子问题的方式进行求解。在LeetCode中,动态规划标签涵盖了众多经典和优美的算法问题,例如斐波那契数列、矩阵链乘法、背包问题等。 动态规划的核心思想是“记忆化搜索”,即将中间状态保存下来,避免重复计算。通常情况下,我们会使用一张二维表来记录状态转移过程中的中间值,例如动态规划求解斐波那契数列问题时,就可以定义一个二维数组f[i][j],代表第i项斐波那契数列中,第j个元素的值。 在LeetCode中,动态规划标签下有众多难度不同的问题。例如,经典的“爬楼梯”问题,要求我们计算到n级楼梯的方案数。这个问题的解法非常简单,只需要维护一个长度为n的数组,记录到达每一级楼梯的方案数即可。类似的问题还有“零钱兑换”、“乘积最大子数组”、“通配符匹配”等,它们都采用了类似的动态规划思想,通过拆分问题、保存中间状态来求解问题。 需要注意的是,动态规划算法并不是万能的,它虽然可以处理众多经典问题,但在某些场景下并不适用。例如,某些问题的状态转移过程比较复杂,或者状态转移方程中存在多个参数,这些情况下使用动态规划算法可能会变得比较麻烦。此外,动态规划算法也存在一些常见误区,例如错用贪心思想、未考虑边界情况等。 总之,掌握动态规划算法对于LeetCode的学习和解题都非常重要。除了刷题以外,我们还可以通过阅读经典的动态规划书籍,例如《算法竞赛进阶指南》、《算法与数据结构基础》等,来深入理解这种算法思想。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值