leetcode最优解整理(dfs/String/Binary Search/Two pointers/Math/Dynamic programming)

从今天开始将自己做过的leetcode进行整理,争取做到bug-free~

recursive and dfs

1. Two Sum

根据target求两数在数组中的index 
思路:用HashMap(时间复杂度o(n))

public int[] twoSum(int[] numbers, int target) {
        int[] res = new int[2];
        if (numbers == null || numbers.length < 2) {
            return res;
        }
        HashMap map = new HashMap();
        for (int i = 0; i < numbers.length; i++) {
            if (map.containsKey(target - numbers[i])) {
                res[0] = i;
                res[1] = map.get(target - numbers[i]);
                return res;
            } else {
                map.put(numbers[i], i);
            }
        }
        return res;
    }
方法2:敏感关键字array和target,想到二分查找法(但需要一点一点挪low和high指针)。 

排序后,target == numbers[low]+numbers[high],记录copy[low]和copy[high];target >numbers[low]+numbers[high],说明最大的和最小的加一起还小于target,所以小值要取大一点,即low++;target

17. Letter Combinations of a Phone Number

给定string(数字组成),输出在键盘上对应的字母组合。

思路:Backtracking

public List letterCombinations(String digits) {
    LinkedList ans = new LinkedList();
    String[] mapping = new String[] {"0", "1", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    ans.add("");
    for(int i =0; i
	 public List letterCombinations(String digits) {
		List res = new ArrayList();
		if (digits.isEmpty()) { // 必不可少
		    return res;
		}
		res.add("");
		String[] s = {" ", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
		char[] array = digits.toCharArray();
		for (int i = 0; i <= digits.length() - 1; i++) {
			int d = array[i] - '0';
			List list = new ArrayList();
			if (d != 1) {
				for (int j = 0; j < res.size(); j++) { 
					list.add(res.get(j) + s[d].charAt(0));
					list.add(res.get(j) + s[d].charAt(1));
					list.add(res.get(j) + s[d].charAt(2));
					if (d == 7 || d == 9) {
						list.add(res.get(j) + s[d].charAt(3));
					}
				}
			}
			res = list;
		}
		return res;
    }

22. Generate Parentheses

求n对()产生的parentheses
思路:dfs,保证每一对的left必在right前
	public List generateParenthesis(int n) {
		ArrayList res = new ArrayList();
		if (n <= 0) {
			return res;
		}
		dfs(res, "", n, n);
		return res;
	}
	public void dfs(ArrayList res,String tmp,int left,int right) {
		if(left == 0 && right == 0) {
			res.add(tmp);
			return;
		}
		if(left > 0) {
			dfs(res, tmp + "(", left - 1, right);	
		}
		if(left

51. N-Queens

the n-queens puzzle:可以横竖直走,斜对角方向直走(从[0,0]到[n,n]),n行n列填n个Q,求所有可能
思路:backtracking。用一维数组代表每行填的列标号。依次遍历每一行,找到所有可能(Start row by row, and loop through columns
	public List> solveNQueens(int n) {
		List> re = new ArrayList>();
		if(n == 1) {
			List l = new ArrayList();
			l.add("Q");
			re.add(l);
			return re;
		}
		int[] Q = new int[n];
		DFS(n, Q, re, 0);
		return re;
	}
	public static void DFS(int n, int[] Q, List> re, int row) {
		if(row == n) {
			List list = new ArrayList();
			// put 
			for(int i = 0; i < n; i++) {
				String s = "";
				for(int j = 0; j < n; j++) {
					if(Q[i] == j) s += "Q";
					else s += ".";
				}
				list.add(s);
			}
			re.add(list);
		} else {
			for(int j = 0; j < n; j++) { // 每一列
				Q[row] = j;
				if(isValid(row, Q))
					DFS(n, Q, re, row + 1);
			}
		}
	}
	public static boolean isValid(int row, int[] Q) {
		for(int i = 0; i < row; i++) {
			if(Q[row] == Q[i] || Math.abs(Q[row] - Q[i]) == (row - i)) 
				return false;
		}
		return true;
	}

52. N-Queens II           

return the total number of distinct solutions.

和上题一样

public static int count = 0;
	public int totalNQueens(int n) {
		if(n == 1) return 1;
		int[] Q = new int[n];
		int re =DFS(n, Q, 0, 0);
		return re;
	}
	public static int DFS(int n, int[] Q, int row, int count) {
		if(row == n)
			count++;
		else {
			for(int j = 0; j < n; j++) { // 每一列
				Q[row] = j;
				if(isValid(row, Q))
					count = DFS(n, Q, row + 1, count);
			}
		}
		return count;
	}
	public static boolean isValid(int row, int[] Q) {
		for(int i = 0; i < row; i++) {
			if(Q[row] == Q[i] || Math.abs(Q[row] - Q[i]) == (row - i)) 
				return false;
		}
		return true;
	}







200. Number of Islands

Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

11110
11010
11000
00000

Answer: 1

Example 2:

11000
11000
00100
00011

Answer: 3


private int n;
private int m;

public int numIslands(char[][] grid) {
    int count = 0;
    n = grid.length;
    if (n == 0) return 0;
    m = grid[0].length;
    for (int i = 0; i < n; i++){
        for (int j = 0; j < m; j++)
            if (grid[i][j] == '1') {
                DFSMarking(grid, i, j);
                ++count;
            }
    }    
    return count;
}

private void DFSMarking(char[][] grid, int i, int j) {
    if (i < 0 || j < 0 || i >= n || j >= m || grid[i][j] != '1') return;
    grid[i][j] = '0';
    DFSMarking(grid, i + 1, j);
    DFSMarking(grid, i - 1, j);
    DFSMarking(grid, i, j + 1);
    DFSMarking(grid, i, j - 1);
}





String

3.  Longest Substring without repeating characters

思路:1 中心扩展,以每个char为中心找到最大的不重复子集(时间:n*n,不好)

2 map存储遍历的值出现的最后一次位置。若遍历的当前值在map中存在,替换为map中此值位置+1和start的最大值(示例:abba)时间复杂度:o(n)

public int lengthOfLongestSubstring2(String s) {
		if (s.length() == 0) return 0;
		HashMap map = new HashMap();
		int max = 0, start = 0;
		for (int i = 0; i < s.length(); ++i) {
			if (map.containsKey(s.charAt(i))) {
				start = Math.max(start, map.get(s.charAt(i)) + 1);
			}
			map.put(s.charAt(i), i);
			max = Math.max(max, i - start + 1);
		}
		return max;
	}

3 set。两个指针,fast指向j,若not in set中,add;否则用slow除掉start至j的所有值,直到j可以放进来

bug: string为空,s.length()引起NullPointerException

	public int lengthOfLongestSubstring(String s) {
	    int i = 0, j = 0, max = 0;
	    Set set = new HashSet<>();
	    
	    while (j < s.length()) {
	        if (!set.contains(s.charAt(j))) {
	            set.add(s.charAt(j++));
	            max = Math.max(max, set.size());
	        } else {
	            set.remove(s.charAt(i++));
	        }
	    }
	    return max;
	}

5. Longest Palindromic Substring

最长回文字串。
思路:中心扩展。注意以i为中心和i i + 1为中心两情况
public String longestPalindrome(String s) {
        if(s.isEmpty()) return "";
        if(s.length() == 1) return s;
        String longest = "";
        for(int i = 0; i < s.length() - 1; i++) {
        	String s1 = helper(s, i, i);
        	if(s1.length() > longest.length())
        		longest = s1;
        	s1 = helper(s, i, i + 1);
        	if(s1.length() > longest.length()) 
        		longest = s1;
        }
        return longest;
    }
	public static String helper(String s, int l, int r) {
		while(l >= 0 && r <= s.length() - 1 && s.charAt(l) == s.charAt(r)) {
			l--;
			r++;
		}
		return s.substring(l + 1,r);
	}

6. ZigZag Conversion

P   A   H   N
A P L S I I G
Y   I   R
convert("PAYPALISHIRING", 3)  return  "PAHNAPLSIIGYIR"
思路1:while循环,从第一行开始用idx走完直下的部分,再从numRows-2开始斜往上,直到到达第二行结束。注意for中判断是否走到s结尾
	public String convert(String s, int numRows) {
		if (numRows >= s.length()) {
			return s;
		}
		String[] str = new String[numRows];
		for (int i = 0; i < str.length; i++) { // bug point: init(否则为null)
			str[i] = "";
		}
		int i = 0;
		while (i < s.length()) {
			for (int idx = 0; idx < numRows && i < s.length(); idx++) { // 直下
				str[idx] += (s.charAt(i++) + "");
			}
			for (int j = numRows - 2; j >= 1 && i < s.length(); j--) { //bug:i边界
				str[j] += (s.charAt(i++) + "");
			}
		}
		String res = "";
		for (String a : str) {
			res += a;
		}
		return res;
	}
思路2:依次遍历s,用incre表示下一步要走的方向,index表示下一步要填的位置(好理解)

	public String convert3(String s, int numRows) {
	    if(numRows <= 1) return s;
	    StringBuilder[] sb=new StringBuilder[numRows];
	    for(int i = 0; i < sb.length; i++) { // init!
	        sb[i] = new StringBuilder("");
	    }
	    int incre = 1;
	    int index = 0;
	    for(int i = 0; i < s.length(); i++) {
	        sb[index].append(s.charAt(i));
	        if(index == 0){incre = 1;}
	        if(index == numRows - 1){incre = -1;}
	        index += incre;
	    }
	    String re = "";
	    for(int i = 0; i < sb.length; i++) {
	        re += sb[i];
	    }
	    return re.toString();
	}

8. String to Integer (atoi)

和7.Reverse Integer类似。
注意string:抛弃空格、溢出、无效字符、sign(+ or -)
最优思路:base表上一位,乘10加本位时,若base为Integer.MAX_VALUE / 10,这一位大于7,则溢出(因为2147483647最后一位7)。考虑有'-'
	public int myAtoi2(String str) {
		if (str.isEmpty()) {
			return 0;
		}
		int base = 0, sign = 1, i = 0;
		while (str.charAt(i) == ' ') {
			i++;
		}
		if (str.charAt(i) == '-' || str.charAt(i) == '+') { 
			sign = (str.charAt(i++) == '-' ? -1 : 1);   // 注意符号,没标就是+
		}
		while (i < str.length() && str.charAt(i) >= '0' && str.charAt(i) <= '9') {
			if (base > Integer.MAX_VALUE / 10 || (base == Integer.MAX_VALUE / 10 && str.charAt(i) - '0' > 7)) {
				return (sign == 1) ? Integer.MAX_VALUE : Integer.MIN_VALUE; 
			}
			base = base * 10 + (str.charAt(i++) - '0'); // 忘了'0'
		}
		return base * sign;
	}

14. Longest Common Prefix

Arrays.sort()按每个char的字母顺序排,所以只需比较第一个和最后一个(排序的时间复杂度o(nlogn))
	public static String longestCommonPrefix(String[] strs) {
		StringBuilder sb = new StringBuilder();
		if(strs == null || strs.length == 0) 
			return sb.toString();
		
		Arrays.sort(strs);
		char[] start = strs[0].toCharArray();
		char[] end = strs[strs.length - 1].toCharArray();
		
		int j = 0;
		int m = Math.min(start.length , end.length);
		if(start.length == 0 || end.length == 0){
			return sb.toString();
		}
		while(j < m && start[j] == end[j]){
				sb.append(start[j]);
				j++;
		}
		return sb.toString();
	}
	public String longestCommonPrefix(String[] strs) {
	    if (strs == null) return null;
	    if (strs.length == 0) return "";
	    
	    Arrays.sort(strs);
	    char[] first = strs[0].toCharArray();
	    char[] last  = strs[strs.length - 1].toCharArray();
	     
	    int i = 0, len = Math.min(first.length, last.length);
	    while (i < len && first[i] == last[i]) i++;
	    return strs[0].substring(0, i);
	}
	public static String longestCommonPrefix(String[] strs) {
		if (strs == null || strs.length < 1) {
			return "";
		}
		for (int idx = 0; idx < strs[0].length(); idx++) {
			for (int i = 1; i < strs.length; i++) {
				if (strs[i].charAt(idx) != strs[0].charAt(idx)) {
					return strs[0].substring(0, idx);
				}
			}
		}
		return strs[0];
	}

38. Count and Say

count-and-say sequence is the sequence of integers beginning as follows:
1, 11, 21, 1211, 111221, ...
1 is read off as "one 1" or 11.
11 is read off as "two 1s" or 21.
21 is read off as "one 2, then one 1" or 1211.Given an integer n, generate the n th sequence. 
思路:理解错了,以为只有1和2两个数组成。

public String countAndSay(int n) {
		 if(n < 1) return null;
		 String s = "1";
		 String re = "";
		 if(n == 1) return s;
		 re = count(2,n,s + "1");
		 return re;
	 }
	 public static String count(int m,int countnum,String b){
		 String res = "";
		 if(m == countnum) {
			 return b;
		 }
		 int tem = 1;		
		 for(int i = 0; i < b.length() - 1; i++) {			 
			 if(b.charAt(i) == b.charAt(i + 1)) { // 算有几个重复的
				 tem++;
			 }
			 if(b.charAt(i) != b.charAt(i + 1) || (i + 1) == b.length()-1){
				 res += Integer.toString(tem);
				 res += b.charAt(i);
				 tem = 1;
				 if(b.charAt(i) != b.charAt(i + 1) && (i + 1) == b.length() - 1) {
					 res += Integer.toString(tem);
					 res += b.charAt(i + 1);
				 }
			  }
		 }
		 return count(++m, countnum, res);
	 }

58. Length of Last Word           

Given a string s consists of upper/lower-case alphabets and empty space characters' ', return the length of last word in the string.

If the last word does not exist, return 0.

public int lengthOfLastWord(String s) {
        s = s.trim();
        if (s == "") {
        	return 0;
        }
        String[] a = s.split(" ");
        if (a.length == 1) {
        	return s.length();
        }
        return a[a.length - 1].length();
    }
	public int lengthOfLastWord(String s) {
		// trim()去掉字符串首尾的空格
		return s.trim().length() - s.trim().lastIndexOf(" ") - 1;
    }

127. Word Ladder

Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.

public int ladderLength(String start, String end, Set dict) {
		
		Set set1 = new HashSet();
		Set set2 = new HashSet();
		set1.add(start);
		set2.add(end);
		int min = helper(1, set1, set2, dict);
		return min;
	}
	public static int helper(int num, Set set1, Set set2, Set dict) {
		if (set1.isEmpty()) {
			return 0;
		}
		if (set1.size() > set2.size()) {
			return helper(num, set2, set1, dict); // 这一步之前忘了加return
		}
		for (String s : set1) {
			dict.remove(s);                                                                                                                                 
		}
		for (String s : set2) {
			dict.remove(s);
		}
		Set set = new HashSet();
		for (String s : set1) {
			for (int i = 0; i < s.length(); i++) {
				char[] c = s.toCharArray(); // 位置在这里!
				for (char a = 'a'; a <= 'z'; a++) {
					c[i] = a;
					String word = new String(c);
					// found the word
					if (set2.contains(word)) {
                        return num + 1;
                    }
					// not 
					if (dict.contains(word)) {
                        set.add(word);
                    }
				}
			}
		}
		return helper(num + 1, set2, set, dict);
	}
	/*
	 * 方法二:用queue
	 * 每次访问和str相差一位的所有字符串。visited标志所有访问过的
	 */
	public int ladderLength(String start, String end, Set dict) {
		  // Use queue to help BFS
		  Queue queue = new LinkedList();
		  queue.add(start);
		  queue.add(null);
		  
		  // Mark visited word
		  Set visited = new HashSet();
		  visited.add(start);
		  
		  int level = 1;
		  
		  while (!queue.isEmpty()) {
		    String str = queue.poll();
		    
		    if (str != null) {
		      // Modify str's each character (so word distance is 1)
		      for (int i = 0; i < str.length(); i++) {
		        char[] chars = str.toCharArray();
		        
		        for (char c = 'a'; c <= 'z'; c++) {
		          chars[i] = c;
		          
		          String word = new String(chars);
		          
		          // Found the end word
		          if (word.equals(end)) return level + 1;
		          
		          // Put it to the queue
		          if (dict.contains(word) && !visited.contains(word)) {
		            queue.add(word);
		            visited.add(word);
		          }
		        }
		      }
		    } else {
		      level++;
		      if (!queue.isEmpty()) { 
		        queue.add(null);
		      }
		    }
		  }
		  return 0;
		}

151. Reverse Words in a String

Given s = "the sky is blue",
return "blue is sky the".

注意处理时: String[] s1 = s.trim().split(" ");// 两个以上空格,错。"a   b"处理后是a, , , ,b

	/*
	 * 最优
	 * 正则表达式Regex
	 * "\s" is a regex class for any kind of whitespace (space, tab, newline, etc). Since Java uses "\" as an escape character in strings (e.g. for newlines: "\n"),
	 * we need to escape the escape character ;-) 
	 * So it becomes "\\s". The "+" means one or more of them.
	 */
	public String reverseWords2(String s) {
		String[] parts = s.trim().split("\\s+"); // trim去掉两边的空格
		String out = "";
		for (int i = parts.length - 1; i > 0; i--) {
		    out += parts[i] + " ";
		}
		return out + parts[0];
	}
	/*
	 * 另一种
	 */
	public String reverseWords3(String s) {        
	    String[] tmp = s.split("\\s");
	    StringBuilder sb = new StringBuilder();
	    
	    for(int i = 1; i <= tmp.length; i++){
	    	if(tmp[tmp.length - i].equals("")){
	    		continue;
	    	}
	    	
	    	sb.append(tmp[tmp.length - i]);
	    	sb.append(" ");
	    }
	    
	    return sb.toString().trim();
	}










Binary Search(二分法)

4. Median of Two Sorted Arrays(hard)

找两个数组的中位数

思路:分奇偶。奇数是n/2,偶数是n/2 - 1和n/2中值
寻找两个数组中第k大数。等价于寻找并判断两个array中第k/2(从1开始数,即index k/2-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]

	public double findMedianSortedArrays(int[] nums1, int[] nums2) {
		int m = nums1.length;
		int n = nums2.length;
		if ((m + n) % 2 == 0) {
			double x = (double)findKth(nums1, 0, nums2, 0, (m + n) / 2 + 1);  // k传的是第k个,index实则k-1
			double y = (double)findKth(nums1, 0, nums2, 0, (m + n) / 2);
			return (x + y) / 2;
		} else {
			return (double)findKth(nums1, 0, nums2, 0, (m + n) / 2 + 1);
		}
	}
	public static double findKth(int[] a, int astart, int[] b, int bstart, int k) {
		int m = a.length - astart;
		int n = b.length - bstart;
		
		if (m > n) {
			return findKth(b, bstart, a, astart, k);
		}
		if (m == 0) { // 当k = 0,bug
			return b[k - 1];
		}
		if(k == 1) 
			return Math.min(a[astart], b[bstart]);
		
		int partA = Math.min(k / 2, m);
		int partB = k - partA;
		if (a[astart + partA - 1] == b[bstart + partB - 1]) {
			return a[astart + partA - 1]; 
		} else if (a[astart + partA - 1] < b[bstart + partB - 1]) {
			return findKth(a, astart + partA, b, bstart, k - partA);
		} else {
			return findKth(a, astart,b, bstart + partB, k - partB);
		}
	}

29. Divide Two Integers

用非乘除余的方法实现除法

注意正负,dividend或divisor为-2147483648的情况,要转化为long

另一思路:将dividend和divisor都转为负数(不用转long),再计算

	public int divide(int dividend, int divisor) {
		if (divisor == 0 || (dividend == Integer.MIN_VALUE && divisor == -1))
            return Integer.MAX_VALUE;
		if(divisor == 1) return dividend;
		boolean isNeg = (divisor < 0 && dividend > 0) || (dividend < 0 && divisor > 0);
		int res = 0;
		
		long dvd = Math.abs(dividend);
		if(dvd < 0) dvd = -dvd;     // Math.abs(Integer.MINVALUE) 不变
		long dvs = Math.abs(divisor);
		if(dvs < 0) dvs = -dvs;
		while(dvd >= dvs) {
			long temp = dvs;
			long mul = 1;
			while(dvd >= (temp << 1)) {
				temp <<= 1;
				mul <<= 1;
			}
			dvd -= temp;
			res += mul;
		}
		return isNeg? -res : res;
	}

33. Search in Rotated Sorted Array

an array sorted in ascending order is rotated at some pivot unknown to you beforehand.find the index of target

思路:需要明确rotated sorted array的特性,那么就是至少有一侧是排好序的.无论pivot在哪

	public int search(int[] nums, int target) {
		if(nums.length < 1) return -1;
		int low = 0;
		int high = nums.length - 1;
		
		while(low <= high) {
			int mid = (low + high) / 2;
			if(nums[mid] < target) {
				if(nums[mid] > nums[low]) { // 左侧有序
					low = mid + 1;
				} else { 
					if(target > nums[high])
					high = mid - 1;
					else low = mid + 1;
				}
			} else if(nums[mid] > target){ // mid大于target
				if(nums[mid] < nums[high]) {  // 右侧有序
					high = mid - 1;
				} else { 
					if(target < nums[low])
					low = mid + 1;
					else high = mid - 1;
				}
			} else return mid;
		}
		return -1;	
        }

81. Search in Rotated Sorted Array II

和1不同的是duplicates are allowed.Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).Write a function to determine if a given target is in the array.
思路:由于有duplicates,可能有时需要左右都查,只有这种情况为O(n),其余为O(logn)。注意当nums[low]== nums[mid]说明左右都可能有target,这时low++继续查
	public boolean search(int[] nums, int target) {
		if(nums.length < 1) return false;
		int low = 0;
		int high = nums.length - 1;
		while(low <= high) {
			int mid = (low + high) /2;
			if(nums[mid] == target) return true;
			if(nums[mid] > nums[low]) { // 左侧有序
				if (target < nums[mid] && target >= nums[low]) high = mid - 1;
                else low = mid + 1;
			} else if(nums[mid] < nums[low]){ // 右侧有序
				if (target > nums[mid] && target < nums[low]) low = mid + 1;
                else high = mid - 1;
			} else low++; // mid和low为重复值!
		}
		return false;
	}

34. Search for a Range           

给定sorted array和target,求taiget对应的index范围
	public int[] searchRange(int[] nums, int target) {
		int[] re = new int[]{-1,-1};
		if(nums.length == 0) {
	        return re;
	    }
        int l = 0, h = nums.length - 1;
        while (l < h) {
        	int mid = (l + h) / 2;
        	if (nums[mid] < target) {
        		l = mid + 1;
        	} else {
        		h = mid;
        	}
        }
        if (nums[l] != target) {
        	return re;
        }
        re[0] = l;
        h = nums.length - 1;
        while (l < h) {
        	int mid = (l + h) / 2 + 1; // Make mid biased to the right
        	if (nums[mid] > target) {
        		h = mid - 1;
        	} else {
        		l = mid; // 注意因为上面是 / 2 + 1,所以这里若mid + 1为wrong answer
        	}
        }
        
        re[1] = h;
        return re;
	}

50. Pow(x, n)

实现x的n次方

思路:递归调用。考虑n为负的情况

方法二利用比特

	public double myPow(double x, int n) {
		 if (x == 0.0) {
			 return 0.0;
		 }
		 if(n == 0) {
			 return 1;
		 }
		 if(n < 0) {
			 return 1 / x * myPow(1 / x, -(n + 1)); // 考虑n == Integer.MIN_VALUE的情况
		 }
		 if(n == 2) return x * x;
		 if(n % 2 == 0) return myPow(x * x, n / 2);
		 else return x * myPow(x * x, n / 2);
	 }

	public double myPow(double x, int n) {
		 if(n==0) return 1;
		 if(n < 0) {
			 n = - n;
			 x = 1 / x;
		 }
		 double ans = 1;
		 while(n > 0){
			 if((n & 1) > 0) ans *= x;
			 x *= x;
			 n >>= 1;
		 }
		 return ans;
	 }
	public static double Pow(double base, int exponent) {
		if (base == 0.0 || exponent == 1) {
			return base;
		}
		if (exponent == 0) {
			return 1;
		}
		if (exponent == 1) {
			return base;
		}
		double res = Pow(base, exponent >> 1);
		res *= res;
		if ((exponent & 1) == 1) { // 奇数与1为1,偶数为0,注意这里:exponent & 1一定要加括号,优先级!
			res *= base;
		}
		return res;
	}





 
  

69. Sqrt(x)           

求平方根

思路:x的平方根在1和x之间,利用left和right找到

方法2采用位运算,差不多

    public int sqrt(int x) {
    	if(x == 0) return 0;
    	int left = 1;
    	int right = x;
    	while(true) {
    		int mid = left + (right - left) / 2;
    		if(mid > x / mid) right = mid - 1;
    		else {
    			if(mid + 1 > x / (mid + 1)) return mid;
    			left = mid + 1;
    		}
    	}
    	return mid;
    }
public int sqrt(int x) {
    	if(x == 0) return 0;
    	int h = 0;
    	while((long)(1<		h++;
    	}
    	h--;
    	int b = h - 1; // 从下一位开始
    	int res = 1 << h;
    	while(b >= 0) {
    		if((long)(res | (1 << b)) * (long) (res | (1 << b)) <= x)
    			res |= (1 << b); // res加上下一位二进制数
    		b--;
    	}
    	return res;
    }

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;
	}
 
   

Two pointers

11. Container With Most Water

题:输入数组表示每条线的高,找到两条线,与x轴组成形状的盛水量最大。

思路设置两个指针i,j,一头一尾。假设i指向的挡板较低,j较高(height[i] < height[j]),下一步移动哪个指针?

若移动j,无论height[j - 1]是何种高度,形成的面积都小于之前的面积;

若移动i,若height[i+1] <= height[i]面积一定缩小。但若height[i+1] > height[i]面积可能增大。综上,应该移动指向较低挡板的那个指针。


	public int maxArea(int[] height) {
	        if (height == null || height.length == 0) {
	        	return 0; 
	        }
	        int max = 0;
	        int i = 0, j = height.length-1;
	        while (i < j) {
	            max = Math.max(max, (j - i) * Math.min(height[i], height[j]));
	            if (height[i] < height[j]) {  // should move i
	                int k; 
	                for (k = i + 1; k < j && height[k] <= height[i]; ++k) {}
	                i = k;
	            } else {  // should move j
	                int k;
	                for (k = j - 1; k > i && height[k] <= height[j]; --k) {}
	                j = k;
	            }
	        }
	        return max;
	    }
或:

	 public int maxArea(int[] height) {  
		  if (height.length < 2) return 0;  
	      int ans = 0;  
	      int l = 0;  
	      int r = height.length - 1; 
	      while (l < r) {
	    	 ans = Math.max(ans, (r - l) * Math.min(height[l], height[r]));
	    	 if (height[l] < height[r]) l++;
	    	 else r--;
 	      }
	      return ans;
	  }

15. 3Sum

a + b + c = 0的所有集合

思路:两个指针代表第2、3个。遍历第一个数时,大于0则不可能。注意去掉duplicate

 
   
	public List> threeSum(int[] nums) {
		List> res = new ArrayList<>();
		if(nums.length < 3) return res;
		for (int i = 0; i < nums.length - 2; i++) {
			if (nums[i] > 0) {
				return res;
			}
			if (i == 0 || nums[i] != nums[i - 1]) {
				int l = i + 1;
				int h = nums.length - 1;
				while (l < h) {
					int sum = nums[i] + nums[h] + nums[l];
					if (sum == 0) {
						res.add(Arrays.asList(nums[i], nums[l], nums[h]));
					}
					if (sum <= 0) {
						while (nums[l] == nums[++l] && l < h);  // l < h 容易忘
					}
					if (sum >= 0) {
						while (nums[h] == nums[--h] && l < h);
					}
				}
			}
		}
		return res;
	}

 
    
 
    

16. 3Sum Closest

3sum的变体,如果没有3sum==target,要返回最接近target的值。
思路:
需要在使用二分查找法时遍历数组的时候,维护一个最接近target值min。
这道题比3sum和4sum简单的地方就是不需要判断重复问题,因为题目给我们减轻了去重的压力,have exactly one solution。即便要求去重,使用之前说过的两个方法:HashSet和挪动指针法,也可以很容易就去重了。
这里要注意,判断closest的方法是采取target-sum的绝对值与min相比
	public int threeSumClosest(int[] nums, int target) {
		if(nums == null || nums.length < 3)
			return 0;
		int res = 0;
		int min = Integer.MAX_VALUE;
		Arrays.sort(nums);
		for (int i = 0; i < nums.length; i++) {
			int l = i + 1;
			int h = nums.length - 1;
			while (l < h) {
				int sum = nums[i] + nums[l] + nums[h];
				if (target == sum) {
					return sum;
				} else if (target > sum) {
					l++;
				} else {
					h--;
				}
				if (Math.abs(target - sum) < min) {
					min = Math.abs(target - sum);
					res = sum;
				}
			}
		}
		return res;
    }

18. 4Sum

思路:遍历固定一位,再调用3sum,注意谢姐

	public List> fourSum(int[] nums, int target) {
		List> re = new ArrayList>();
		Arrays.sort(nums);
		if (nums == null || nums.length < 4 || 4 * nums[nums.length - 1] < target) {
			return re;
		}
		for (int i = 0; i < nums.length - 3; i++) {
			if(i == 0 || nums[i] != nums[i - 1]) {
				if(4 * nums[i] > target) { // to save time
					break;
				}
				re.addAll(sum3(nums, i + 1, target - nums[i]));	
			}
		}
		return re;
    }
	public static List> sum3 (int[] a, int i, int target) {
		List> result = new ArrayList>();
		for(int j = i; j < a.length - 2; j++) {
			if (j == i || a[j] != a[j - 1]){
				if (a[j] * 3 > target) { // to save time
					break;
				}
				int l = j + 1;
	            int h = a.length - 1;
	            while(l < h) {
	            	int sum = a[j] + a[l] + a[h];
	            	if(sum == target) {
	            		result.add(Arrays.asList(a[i- 1], a[j], a[l], a[h]));
	            	}
	            	if(sum <= target) while(a[l] == a[++l] && l < h);
	                if(sum >= target) while(a[h] == a[--h] && l < h);
	            }
			}
		}
		return result;
	}

26. Remove Duplicates from Sorted Array

输入nums = [1,1,2],不算重复的,个数为2,且nums前两位要为1,2

最优思路:用一个数id记录当前需要赋值的位置,不用管id之后的。当i不等于i-1,将i赋给id

·public int removeDuplicates2(int[] nums) {
		if (nums.length < 2) {
			return nums.length; 
		}
		int id = 1;
		for(int i = 1; i < nums.length; ++i) 
        if(nums[i] != nums[i - 1]) {
        	nums[id++] = nums[i];
        }
        return id;
	}

27. Remove Element

给定val,remove所有值为val的点,其余点排在前面

思路和#26一样

public int removeElement(int[] nums, int val) {
        int id = 0;
		for (int i = 0; i < nums.length; i++) {
			if (nums[i] != val) {
				nums[id] = nums[i];
				id++;
			}
			
		}
		return id;
    }

28. Implement strStr()

求字符串中出现的string的index
public int strStr(String haystack, String needle) {
		if(haystack == null || needle == null)    
            return 0;
		return haystack.indexOf(needle);
    }
不用indexOf()的方法
public int strStr(String haystack, String needle) {
  for (int i = 0; ; i++) {
    for (int j = 0; ; j++) {
      if (j == needle.length()) return i;
      if (i + j == haystack.length()) return -1;
      if (needle.charAt(j) != haystack.charAt(i + j)) break;
    }
  }
}

75. Sort Colors

0、1、2代表三种颜色,按顺序在数组中排序(不能用sort function)

两指针

public void sortColors(int[] nums) {		
		if(nums.length <= 1) return;
        int color1 = 0, color3 = nums.length - 1;
        for (int i = 0; i <= color3 && color1 < color3; i++) {
        	if (nums[i] == 0 && i > color1) { 
        		swap(nums, i--, color1++);
        		
        	} else if (nums[i] == 2 && i < color3) {
        		swap(nums, i--, color3--);
        	}
        }
    }
	public void swap(int[] b, int left, int right){
		if(left == right) return;
		b[left] = b[left] + b[right];
		b[right] = b[left] - b[right];
		b[left] = b[left] - b[right];
	}

125. Valid Palindrome

"A man, a plan, a canal: Panama" is a palindrome.

"race a car" is not a palindrome.

/*
	 * 最优
	 */
	  public boolean isPalindrome2(String s) {
	        if (s.isEmpty()) {
	        	return true;
	        }
	        int head = 0, tail = s.length() - 1;
	        char cHead, cTail;
	        while(head <= tail) {
	        	cHead = s.charAt(head);
	        	cTail = s.charAt(tail);
	        	if (!Character.isLetterOrDigit(cHead)) {
	        		head++;
	        	} else if(!Character.isLetterOrDigit(cTail)) {
	        		tail--;
	        	} else {
	        		if (Character.toLowerCase(cHead) != Character.toLowerCase(cTail)) {
	        			return false;
	        		}
	        		head++;
	        		tail--;
	        	}
	        }
	        
	        return true;
	    }
	  /*
	   * simple,but slow
	   */
	  public boolean isPalindrome3(String s) {
	        String actual = s.replaceAll("[^A-Za-z0-9]", "").toLowerCase();
	        String rev = new StringBuffer(actual).reverse().toString();
	        return actual.equals(rev);
	   }


 
    

Math

7. Reverse Integer

考虑reverse后溢出的情况(负数余正数为负)

public int reverse(int x) {
		int result = 0;
	    while(x != 0){
	    	int d = x % 10;
	    	if(Math.abs(result) > Integer.MAX_VALUE / 10) {// 关键 
	    		return 0;
	    	}
	    	result = result * 10 + d;
	    	x /= 10;
	    }
	    return result;
	}




 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  

 
  

9. Palindrome Number

判断回文数

	boolean isPalindrome(int x) {
		if (x < 0) return false; // 负数没有回文数
		int d = 1; //divisor
		while (x / d > 10) {
			d *= 10;
		}
		while (x > 0) {
			int q = x / d;
			int r = x % 10;
			if (q != r) {
				return false;
			}
			x = x % d /10; // bug point
			d = d / 100;
		}
		return true;
	}
最优解:
public boolean isPalindrome(int x) {
     if (x<0 || (x!=0 && x%10==0)) return false;
     int rev = 0;
     while (x>rev){
      rev = rev*10 + x%10;
      x = x/10;
      System.out.println(rev + " " + x) ;
     }
     return (x==rev || x==rev/10);
 }

12. Integer to Roman

 
  

"I","V","X","L","C","D","M"

1, 5, 10, 50,100,500,1000

小数在大数右边为加,左边为减(限I,X,C);连写不能超过三个

	public String intToRoman(int num) {
	    String M[] = {"", "M", "MM", "MMM"}; // 1000- 3000
	    String C[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; // 100-900
	    String X[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; // 10-90
	    String I[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; // 1-9
	    return M[num/1000] + C[(num%1000)/100]+ X[(num%100)/10] + I[num%10];
	}
	public String intToRoman2(int num) {
	    int[] values = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
	    String[] strs = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
	    StringBuilder sb = new StringBuilder();    
	    for(int i = 0; i < values.length; i++) {
	        while(num >= values[i]) {
	            num -= values[i];
	            sb.append(strs[i]);
	        }
	    }
	    return sb.toString();
	}

12. Roman to Integer

思路:倒序遍历,比上一个大则加,小则减
 public int romanToInt(String s) {
        if(s == null || s.length() == 0) return 0;
        int len = s.length();
        HashMap map = new HashMap();
        map.put('I',1);
        map.put('V',5);
        map.put('X',10);
        map.put('L',50);
        map.put('C',100);
        map.put('D',500);
        map.put('M',1000);
        int result = map.get(s.charAt(len -1));
        int pivot = result;
        for(int i = len - 2; i>= 0;i--) {
            int curr = map.get(s.charAt(i));
            if(curr >=  pivot){
                result += curr;
            }else{
                result -= curr;
            }
            pivot = curr;
        }
        return result;
    }
	public static int romantoInt(String s) {
		int sum = 0;
		if (s.contains("IV")) {
			sum -= 2;
		}
		if (s.contains("IX")) {
			sum -= 2;
		}
		if (s.contains("XL")) {
			sum -= 20;
		}
		if (s.contains("XC")) {
			sum -= 20;
		}
		if (s.contains("CD")) {
			sum -= 200;
		}
		if (s.contains("CM")) {
			sum -= 200;
		}
		char[] c = s.toCharArray();
		for(int i = 0; i < c.length; i++) {
			if (c[i] == 'M') {
				sum += 1000;
			}
			if (c[i] == 'D') {
				sum += 500;
			}
			if (c[i] == 'C') {
				sum += 100;
			}
			if (c[i] == 'L') {
				sum += 50;
			}
			if (c[i] == 'X') {
				sum += 10;
			}
			if (c[i] == 'V') {
				sum += 5;
			}
			if (c[i] == 'I') {
				sum += 1;
			}
		}
	}

43. Multiply Strings

两个string(length < 110)相乘
思路:直接乘会溢出,所以每次都要两个single digit相乘,最大81,不会溢出。比如385 * 97, 就是个位=5 * 7,十位=8 * 7 + 5 * 9 ,百位=3 * 7 + 8 * 9 …

可以每一位用一个Int表示,存在int[]里面;这个数组最大长度是num1.len +num2.len,比如99 * 99,最大不会超过10000,所以4位就够了。这种个位在后面的,不好做(10的0次方,可惜对应位的数组index不是0而是n-1),所以干脆先把string reverse了代码就清晰好多。注意最后结果前面的0要清掉。


public String multiply(String num1, String num2) {
        char[] c1 = new StringBuilder(num1).reverse().toString().toCharArray();
        char[] c2 = new StringBuilder(num2).reverse().toString().toCharArray();
        int m = c1.length + c2.length;
        int[] re = new int[m];
        int carry = 0;
        for (int i = 0; i < c1.length; i++) {
        	int a = c1[i] - '0';
        	for(int j = 0; j < c2.length;j++){
        		int b = c2[j] - '0';
            	re[i + j] += a * b; // re[i + j]
        	}
        }
        carry = re[0] / 10;
        re[0] = re[0] % 10;
        StringBuilder sb = new StringBuilder();
        sb.append(re[0] + "");
       for (int i = 1; i < re.length; i++) {
    	   re[i] = carry + re[i];
    	   carry = re[i]  / 10;
    	   sb.insert(0,(re[i] % 10) + ""); // 放在最前
       }
       while(sb.length() > 0 && sb.charAt(0)=='0') {
			  sb.deleteCharAt(0);
		  }
       return sb.length() == 0 ? "0" : sb.toString(); // bug :忘记判断0乘以0的情况
    }

67. Add Binary           

相加两个二进制数

是将数组反转,然后相加,c1[i]+ c2[i] + carry有4种值:0,1,2,3,因此:sum % 2为本位,sum /2为进位,bug  free
两个思路差不多,实现稍不一样
public String addBinary(String a, String b) {
        char[] c1 = new StringBuilder(a).reverse().toString().toCharArray();
        char[] c2 = new StringBuilder(b).reverse().toString().toCharArray();
        int i = 0;
        StringBuilder res = new StringBuilder();
        int carry = 0;
        while (i < c1.length || i < c2.length) {
        	int sum = carry;
        	if (i < c1.length) {
        		sum += (c1[i] - '0');
        	}
        	if (i < c2.length) {
        		sum += (c2[i] - '0');
        	}
        	res.append(sum % 2);
        	carry = (sum / 2);
        	i++;
        }
        if (carry == 1) {
        	res.append("1");
        }
        return res.reverse().toString();
    }

	public String addBinary(String a, String b) {
		 if(a == null || a.isEmpty()) 
	            return b;
		 if(b == null || b.isEmpty()) 
	            return a;
		 StringBuilder sb = new StringBuilder();
		 int i = a.length() - 1;
		 int j = b.length() - 1;
		 int aBit;
		 int bBit;
		 int carry = 0;
		 int result;
		 while(i >= 0 || j >= 0 || carry == 1) {
	            aBit = (i >= 0) ? Character.getNumericValue(a.charAt(i--)) : 0;
	            bBit = (j >= 0) ? Character.getNumericValue(b.charAt(j--)) : 0;
	            result = aBit ^ bBit ^ carry;
	            carry = ((aBit + bBit + carry) >= 2) ? 1 : 0;
	            sb.append(result);
	        }
	        return sb.reverse().toString();
	}

168. Excel Sheet Column Title

1 -> A
    2 -> B
    3 -> C
    ...
    26 -> Z
    27 -> AA
    28 -> AB 
Given a positive integer, return its corresponding column title as appear in an Excel sheet.

public String convertToTitle(int n) {
		return n == 0 ? "" : convertToTitle(--n / 26) + (char)('A' + (n % 26));
	}
	public String convertToTitle2(int n) {
        StringBuilder result = new StringBuilder();
        while(n > 0) {
            n--;
            result.insert(0, (char)('A' + n % 26));
            n /= 26;
        }
        return result.toString();
     }



dynamic programing

44. Wildcard Matching

模糊匹配。
'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).意思是任何字符串
思路:动态规划。长度为a和b的两个字符串是否匹配,有两种情况:
s 的第i位和p的第j位相同(或为‘?’),则 dp[i][j] = dp[i - 1][j - 1]
p的第j位为‘*’则dp[i][j] = dp[i - 1][j] || dp[i][j - 1](dp[i][j - 1]意思是*代表空,dp[i - 1][j]则*为一个字符)
public static boolean isMatch(String s, String p) {
		int m = s.length();
		int n = p.length();
		boolean[][] dp = new boolean[m + 1][n + 1];
		char[] ws = s.toCharArray();
        char[] wp = p.toCharArray();
        
        dp[0][0] = true;
        for (int i = 1; i <= n; i++) {
        	dp[0][i] = dp[0][i - 1] && wp[i - 1] == '*';
        }
        for (int j = 1; j <= m; j++) {
        	dp[j][0] = false;
        }
        
        for (int i = 1; i <= m; i++) {
        	for (int j = 1; j <= n; j++) {
            	if (wp[j - 1] == '?' || ws[i - 1] == wp[j - 1]) 
            		dp[i][j] = dp[i - 1][j - 1];
            	else if (wp[j - 1] == '*')
            		dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
            }
        }
        return dp[m][n];
	}

53. Maximum Subarray

Find the contiguous subarray within an array (containi
	public int maxSubArray(int[] nums) {
		if (nums.length < 1) {
			return 0;
		}
		int[] dp = new int[nums.length];
		int max = nums[0];
		dp[0] = nums[0];
		for (int i = 1; i < nums.length; i++) {
			if (dp[i - 1] + nums[i] > nums[i]) {
				dp[i] = dp[i - 1] + nums[i];
			} else {
				dp[i] = nums[i];
			}
			if (dp[i] > max) {
				max = dp[i];
			}
		}
		return max;
    }

ng at least one number) which has the largest sum

要想起来用dp。当前位置的最大值取决于前一个sum。本题bug free

62. Unique Paths

m行n列从左上至右下路径个数。

简单dp,bug-free

public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        dp[0][0] = 1;
        for (int i = 1; i < n; i++) {
        	dp[0][i] = 1;
        }
        for (int i = 1; i < m; i++) {
        	dp[i][0] = 1;
        }
        for (int i = 1; i < m; i++) {
        	for (int j = 1; j < n; j++) {
        		dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        	} 
        }
        return dp[m - 1][n - 1];
    }

63. Unique Paths II           

加入了障碍(1),可以用上面一样的方法,注意去掉0,0处为1的情况

思路2:用一维dp数组。

因为只需要求dp[m-1][n-1],所以先横向再竖向扫描,依次得到每一行的每一列dp[j],然后每行取决于上一行。

每一个点[i,j]都是由每一行的j - 1列相加得到的(依次更新每一行的dp[j])

	public int uniquePathsWithObstacles(int[][] obstacleGrid) {
		int m = obstacleGrid.length;
		int n = obstacleGrid[0].length;
		int[][] dp = new int[m][n];
		if (obstacleGrid[0][0] == 0) {
			return 0;
		}
        dp[0][0] = 1;
        for (int i = 1; i < n && obstacleGrid[0][i] != 1; i++) {
        	dp[0][i] = 1;
        }
        for (int i = 1; i < m && obstacleGrid[i][0] != 1; i++) {
        	dp[i][0] = 1;
        }
        for (int i = 1; i < m; i++) {
        	for (int j = 1; j < n; j++) {
        		if (obstacleGrid[i][j] == 1) {
        			dp[i][j] = 0;
        		} else {
        			dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        		}
        	} 
        }
        return dp[m - 1][n - 1];
    }

	public int uniquePathsWithObstacles(int[][] obstacleGrid) {
		int n = obstacleGrid[0].length;
		int[] dp = new int[n];
		dp[0] = 1;
		for (int[] row : obstacleGrid) {
			for (int j = 0; j < n; j++) {
				if (row[j] == 1)
					dp[j] = 0;
				else if (j > 0)
					dp[j] += dp[j - 1];
			}
		}
		    return dp[n - 1];
    }



64. Minimum Path Sum

每个位置都有值,求左上至右下最小的路径值

和63一样,一维dp

	public int minPathSum(int[][] grid) {
        int n = grid[0].length;
        int[] dp = new int[n];
        for (int i = 0; i < grid.length; i++) {
        	for (int j = 0; j < n; j++) {
        		if (i == 0 && j > 0)  {
        			dp[j] = grid[i][j] + dp[j - 1];
        		} else {
        			if (j == 0) {
            			dp[j] += grid[i][0]; // dp[0][0]
            		} else {
            			dp[j] = grid[i][j] + Math.min(dp[j], dp[j - 1]);
            		}
        		}
        	}
        }
        return dp[n - 1];
    }

70. Climbing Stairs           

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top(n层)

每一层来自上一层走一步,或者上上层走两步。即dp[i] = dp[i - 1] + dp[i - 2]

	public int climbStairs(int n) {
		if (n <= 0) {
			return 0;
		}
		if (n <= 2) {
			return n;
		}
		int[] dp = new int[2];
		dp[0] = 1;
		dp[1] = 2;
		for (int i = 2; i < n; i++) {
			dp[i % 2] = dp[(i - 1) % 2] + dp[(i - 2) % 2];
		}
		return dp[(n - 1) % 2];
	}

递归也可以做,但是超时(递归的层数太多,需要的内存也指数级递增)

public int climbStairs(int n) {
		if (n <= 0) {
			return 0;
		}
		if (n <= 2) {
			return n;
		}
		return climbStairs(n - 1) + climbStairs(n - 2);
	}

91. Decode Ways

A message containing letters from A-Z is being encoded to numbers using the following mapping:

'A' -> 1
'B' -> 2
...
'Z' -> 26

Given an encoded message containing digits, determine the total number of ways to decode it.For example,Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12).The number of ways decoding "12" is 2.

思路:易忽略nums[i] = 0,当前一个nums[i - 1]>=3,num[i] == 0,非法。另外,nums[i]并不仅是nums[i - 1]+ 1,例:"121"有三种,"1212"有5种
所以正确思路是:nums[i]单独组,则dp[i] += dp[i - 1],nums[i]和nums[i-1]一起,则dp[i]+=dp[i -2]
public int numDecodings(String s) {
        if(s == null || s.length() == 0 || s.charAt(0) == '0') {
            return 0;
        }
        int n = s.length();
        int[] dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = s.charAt(0) != '0' ? 1 : 0;
        for(int i = 2; i <= n; i++) {
            int first = Integer.valueOf(s.substring(i-1, i));
            int second = Integer.valueOf(s.substring(i-2, i));
            if(first >= 1 && first <= 9) {
               dp[i] += dp[i-1];  
            }
            if(second >= 10 && second <= 26) {
                dp[i] += dp[i-2];
            }
        }
        return dp[n];
    }


 
  

120. Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

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

题目:三角形第一层至最后一层的最小sum,只能走下一层的相邻点
最优思路(巧妙):一维数组A保存(三角形的高与最大宽相等),从底向上加和

 
   
 
   
 
   
 
   
 
   
 
   
 
   
 
   
 
   
 
  

	public int minimumTotal2(List> triangle) {
	    int[] A = new int[triangle.size() + 1];
	    for(int i = triangle.size() - 1 ; i >= 0; i--) {
	        for(int j = 0; j < triangle.get(i).size(); j++) {
	            A[j] = Math.min(A[j], A[j + 1]) + triangle.get(i).get(j);
	        }
	    }
	    return A[0];
	}
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
 

你可能感兴趣的:(leetcode最优解)