面试题 08.11. 硬币凑整 给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)
 
  示例1:
  输入: n = 5 
  输出:2 
  解释: 有两种方式可以凑成总金额: 5=5 5=1+1+1+1+1
  示例2:
  输入: n = 10 
  输出:4 
  解释: 有四种方式可以凑成总金额: 10=10 10=5+5 10=5+1+1+1+1+1 10=1+1+1+1+1+1+1+1+1+1
  说明:
  你可以假设:0 <= n (总金额) <= 1000000
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Solution   {    public  int  waysToChange (int  n)   {                int [] dp = new  int [n + 1 ];               int [] coins = new  int []{1 ,5 ,10 ,25 };                                    dp[0 ] = 1 ;                  for (int  coin : coins) {             for (int  i = coin; i <= n; i++) {                 dp[i] = (dp[i] + dp[i - coin]) % 1000000007 ;             }         }         return  dp[n];     } } 
 
面试题51. 数组中的逆序对 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
  示例 1:
  输入: [7,5,6,4]
  输出: 5
  限制:0 <= 数组长度 <= 50000
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class  Solution   {    public  int  reversePairs (int [] nums)   {         return  merge(nums, 0 , nums.length - 1 );     }     int  merge (int [] arr, int  start, int  end)   {         if  (start >= end) return  0 ;         int  mid = start + (end - start) / 2 ;         int  count = merge(arr, start, mid) + merge(arr, mid + 1 , end);         int [] temp = new  int [end - start + 1 ];         int  i = start, j = mid + 1 , k = 0 ;         while  (i <= mid && j <= end) {             count += arr[i] <= arr[j] ? j - (mid + 1 ) : 0 ;             temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];         }         while  (i <= mid) {             count += j - (mid + 1 );             temp[k++] = arr[i++];         }         while  (j <= end){             temp[k++] = arr[j++];         }           System.arraycopy(temp, 0 , arr, start, end - start + 1 );         return  count;     } } 
 
3. 无重复字符的最长子串 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
  示例 1:
  输入: “abcabcbb”
  输出: 3 
  解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
  示例 2:
  输入: “bbbbb”
  输出: 1
  解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
  示例 3:
  输入: “pwwkew”
  输出: 3
  解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
  请注意,你的答案必须是 子串 的长度,”pwke” 是一个子序列,不是子串。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class  Solution   {    public  int  lengthOfLongestSubstring (String s)   {         if  (s.length()==0 ) {             return  0 ;         }         HashMap map = new  HashMap();                    int  max = 0 ;                  int  left = 0 ;         for (int  i = 0 ; i < s.length(); i ++){             if (map.containsKey(s.charAt(i))){                                  left = Math.max(left,map.get(s.charAt(i)) + 1 );             }             map.put(s.charAt(i),i);             max = Math.max(max,i-left+1 );         }         return  max;     } } 
 
4. 寻找两个正序数组的中位数 给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
  示例 1:
  nums1 = [1, 3]
  nums2 = [2]
  则中位数是 2.0
  示例 2:
  nums1 = [1, 2]
  nums2 = [3, 4]
  则中位数是 (2 + 3)/2 = 2.5
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 class  Solution   {    public  double  findMedianSortedArrays (int [] nums1, int [] nums2)   {         int  m = nums1.length;         int  n = nums2.length;                  int [] nums = new  int [m + n];                  if  (m == 0 ) {                          if  (n % 2  == 0 ) {                 return  (nums2[n / 2  - 1 ] + nums2[n / 2 ]) / 2.0 ;             } else  {                 return  nums2[n / 2 ];             }         }                  if  (n == 0 ) {                          if  (m % 2  == 0 ) {                 return  (nums1[m / 2  - 1 ] + nums1[m / 2 ]) / 2.0 ;             } else  {                 return  nums1[m / 2 ];             }         }                  int  count = 0 ;                  int  i = 0 , j = 0 ;                  while  (count != (m + n)) {                          if  (i == m) {                 while  (j != n) {                     nums[count++] = nums2[j++];                 }                 break ;             }                          if  (j == n) {                 while  (i != m) {                     nums[count++] = nums1[i++];                 }                 break ;             }                          if  (nums1[i] < nums2[j]) {                 nums[count++] = nums1[i++];             } else  {                 nums[count++] = nums2[j++];             }         }                  if  (count % 2  == 0 ) {             return  (nums[count / 2  - 1 ] + nums[count / 2 ]) / 2.0 ;         } else  {             return  nums[count / 2 ];         }     } } 
 
5. 最长回文子串 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
  示例 1:
  输入: “babad”
  输出: “bab”
  注意: “aba” 也是一个有效答案。
  示例 2:
  输入: “cbbd”
  输出: “bb”
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class  Solution   {    public  String longestPalindrome (String s)   {         if (s == null  || s.equals("" )){             return  s;         }                           boolean [][] dp = new  boolean [s.length()][s.length()];                           int  min = 0 , max = 0 ;                           for (int  i = 0 ; i < s.length(); i++) {             dp[i][i] = true ;         }                           for (int  i = s.length() - 1 ; i >= 0 ; i--){             for (int  j = i + 1 ; j < s.length(); j++){                 if (s.charAt(i) == s.charAt(j)) {                                          if (j - i == 1 ){                         dp[i][j] = true ;                     }else {                                              dp[i][j] = dp[i+1 ][j-1 ];                      }                 }else {                     dp[i][j] = false ;                 }                 if (dp[i][j]){                                          if (max - min <= j - i){                         min = i;                         max = j;                     }                 }             }         }         return  s.substring(min, max + 1 );     } } 
 
11. 盛最多水的容器 给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
  说明:你不能倾斜容器,且 n 的值至少为 2。
  示例:
  输入:[1,8,6,2,5,4,8,3,7]
  输出:49
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class  Solution   {    public  int  maxArea (int [] height)   {         int  res = 0 , i = 0 , j = height.length - 1 ;         while  (i < j){             if (height[i] <= height[j]){                 res = Math.max(res, height[i] * (j - i));                 i++;             }else {                 res = Math.max(res, height[j] * (j - i));                 j--;             }         }         return  res;     } } 
 
23. 合并K个排序链表 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
  示例:
  输入:   [     1->4->5,     1->3->4,     2->6   ]
  输出: 1->1->2->3->4->4->5->6
 
利用堆做排序 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class  Solution   {    public  ListNode mergeKLists (ListNode[] lists)   {         if (lists==null  || lists.length==0 ) {             return  null ;         }                  PriorityQueue queue = new  PriorityQueue(new  Comparator() {               public  int  compare (ListNode o1, ListNode o2)   {                 return  (o1.val - o2.val);             }         }); 		 		for (int  i = 0 ;i < lists.length; i++) { 			while (lists[i] != null ) { 				queue.add(lists[i]); 				lists[i] = lists[i].next; 			} 		}            ListNode dummy = new  ListNode(-1 );         ListNode head = dummy;                  while ( !queue.isEmpty() ) {             dummy.next = queue.poll();             dummy = dummy.next;         }         dummy.next = null ;         return  head.next;     } } 
 
堆排序优化 
我们建立完k个大小的堆后,就不断的从堆中获取节点,如果获取到的节点不为空,即还有下一个节点,那么就将下一个节点放到堆中。利用这个特点我们就可以优化空间了,将原先的O(N)的空间复杂度优化到O(k)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class  Solution   {    public  ListNode mergeKLists (ListNode[] lists)   {         if (lists==null  || lists.length==0 ) {             return  null ;         }                  PriorityQueue queue = new  PriorityQueue(new  Comparator() {               public  int  compare (ListNode o1, ListNode o2)   {                 return  (o1.val - o2.val);             }         });         ListNode dummy = new  ListNode(-1 );         ListNode cur = dummy;                           for (int  i = 0 ; i < lists.length; i++) {             ListNode head = lists[i];             if (head!=null ) {                 queue.add(head);             }         }                           while (queue.size() > 0 ) {             ListNode node = queue.poll();             cur.next = node;             cur = cur.next;             if (node.next!=null ) {                 queue.add(node.next);             }         }         cur.next = null ;         return  dummy.next;     } } 
 
两两合并 
对于这四个链表,我们先合并A1和A2,将这两个链表变成A1-A2,然后再按照两两合并的方式,合并A1-A2和A3,这三个链表就合并成了A1-A2-A3,最后将A1-A2-A3跟A4两两合并,四个链表就合并完了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class  Solution   {    public  ListNode mergeKLists (ListNode[] lists)   {         if (lists==null  || lists.length==0 ) {             return  null ;         }                           ListNode res = lists[0 ];         for (int  i=1 ;i            res = merge(res,lists[i]);         }         return  res;     }          private  ListNode merge (ListNode a, ListNode b)   {         if (a==null  || b==null ) {             return  (a==null ) ? b : a;         }         if (a.val<=b.val) {             a.next = merge(a.next,b);             return  a;         } else  {             b.next = merge(a,b.next);             return  b;         }     } }  
 
35. 搜索插入位置 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
  示例 1:
  输入: [1,3,5,6], 5
  输出: 2
  示例 2:
  输入: [1,3,5,6], 2
  输出: 1
  示例 3:
  输入: [1,3,5,6], 7
  输出: 4
  示例 4:
  输入: [1,3,5,6], 0
  输出: 0
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class  Solution   {    public  int  searchInsert (int [] nums, int  target)   {                  int  low = -1 ;                  int  high = nums.length;                  while (low + 1  < high){             int  mid = (low + high) / 2 ;             if (nums[mid] >= target){                 high = mid;             }else {                 low = mid;             }         }         return  high;     } } 
 
46. 全排列 给定一个 没有重复 数字的序列,返回其所有可能的全排列。
  示例:
  输入: [1,2,3]
  输出:   [     [1,2,3],     [1,3,2],     [2,1,3],     [2,3,1],     [3,1,2],     [3,2,1]   ]
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class  Solution   {    List> res = new  LinkedList<>();
          public  List> permute(int [] nums) {
                  LinkedList track = new  LinkedList<>();          backtrack(nums, track);         return  res;     }                    void  backtrack (int [] nums, LinkedList track)    {                  if  (track.size() == nums.length) {             res.add(new  LinkedList(track));             return ;         }                  for  (int  i = 0 ; i < nums.length; i++) {                          if  (track.contains(nums[i]))                 continue ;                          track.add(nums[i]);                          backtrack(nums, track);                          track.removeLast();         }     } } 
 
55. 跳跃游戏 给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
  示例 1:
  输入: [2,3,1,1,4]
  输出: true
  解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
  示例 2:
  输入: [3,2,1,0,4]
  输出: false
  解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class  Solution   {    public  boolean  canJump (int [] nums)   {                  int  maxLen = 0 ;         for (int  i = 0 ; i < nums.length; i++){                          if (i > maxLen){                 return  false ;             }                          maxLen = Math.max(maxLen, i + nums[i]);         }         return  true ;     } } 
 
76. 最小覆盖子串 给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
  示例:
  输入: S = “ADOBECODEBANC”, T = “ABC”
  输出: “BANC”
  说明:
  如果 S 中不存这样的子串,则返回空字符串 “”。
  如果 S 中存在这样的子串,我们保证它是唯一的答案。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class  Solution   {    public  static  String minWindow (String s, String t)   {         if  (s == null  || s == ""  || t == null  || t == ""           || s.length() < t.length()) {             return  "" ;         }                  int [] needs = new  int [128 ];                  int [] window = new  int [128 ];                  for  (int  i = 0 ; i < t.length(); i++) {             needs[t.charAt(i)]++;         }                  int  left = 0 ;         int  right = 0 ;         String res = "" ;                  int  count = 0 ;                  int  minLength = s.length() + 1 ;         while  (right < s.length()) {             char  ch = s.charAt(right);             window[ch]++;             if  (needs[ch] > 0  && needs[ch] >= window[ch]) {                 count++;             }                          while  (count == t.length()) {                 ch = s.charAt(left);                 if  (needs[ch] > 0  && needs[ch] >= window[ch]) {                     count--;                 }                 if  (right - left + 1  < minLength) {                     minLength = right - left + 1 ;                     res = s.substring(left, right + 1 );                 }                 window[ch]--;                 left++;             }             right++;         }         return  res;     } } 
 
84. 柱状图中最大的矩形 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
  示例:
  输入: [2,1,5,6,2,3]
  输出: 10
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class  Solution   {    public  int  largestRectangleArea (int [] heights)   {         return  largestRectangleArea(heights, 0 , heights.length-1 );     }     public  int  largestRectangleArea (int [] heights, int  left, int  right)   {         if  (left > right) {             return  0 ;         }         if  (right == left) {             return  heights[left];         }                  int  minHeight = heights[left];                  int  minHeightIndex = left;                  for  (int  i = left; i <= right; i++) {             if  (heights[i] < minHeight) {                 minHeight = heights[i];                 minHeightIndex = i;             }         }                  return  Math.max(             minHeight * (right - left + 1 ),              Math.max(largestRectangleArea(heights, left, minHeightIndex - 1 ),                          							 largestRectangleArea(heights, minHeightIndex + 1 , right)));     } } 
 
101. 对称二叉树 给定一个二叉树,检查它是否是镜像对称的。
  例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
 
1 2 3 4 5 	1    / \   2   2  / \ / \ 3  4 4  3 
 
  但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class  Solution   {    public  boolean  isSymmetric (TreeNode root)   {         if  (root == null ) {             return  true ;         } else  {             return  isMirrorBTree(root.left, root.right);         }     }          boolean  isMirrorBTree (TreeNode root1, TreeNode root2)   {         if (null  == root1 && null  == root2) {             return  true ;         }else  if (null  == root1 || null  == root2) {             return  false ;         }         if (root1.val != root2.val) {             return  false ;         }                  return  isMirrorBTree(root1.left,root2.right)             && isMirrorBTree(root1.right,root2.left);     } } 
 
105. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树。
注意:你可以假设树中没有重复的元素。
  例如,给出
  前序遍历 preorder = [3,9,20,15,7]
  中序遍历 inorder = [9,3,15,20,7]
  返回如下的二叉树:
  [3,9,20,15,7]
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import  java.util.Arrays;class  Solution   {    public  TreeNode buildTree (int [] pre, int [] in)   {         if (pre.length == 0  || in.length == 0 ){             return  null ;         }                  TreeNode root = new  TreeNode(pre[0 ]);         for (int  i = 0 ; i < in.length; i++){                          if (pre[0 ] == in[i]){                 root.left = buildTree                     (Arrays.copyOfRange(pre, 1 , i+1 ),                       Arrays.copyOfRange(in, 0 , i));                 root.right = buildTree                     (Arrays.copyOfRange(pre, i+1 , pre.length),                       Arrays.copyOfRange(in, i+1 , in.length));                 break ;             }         }         return  root;     } } 
 
146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
 
写入数据 put(key, value) - 如果密钥已经存在,则变更其数据值;如果密钥不存在,则插入该组「密钥/数据值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
 
 
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
  示例:
  1 2 3 4 5 6 7 8 9 10 LRUCache cache = new  LRUCache( 2   ); cache.put(1 , 1 ); cache.put(2 , 2 ); cache.get(1 );        cache.put(3 , 3 );     cache.get(2 );        cache.put(4 , 4 );     cache.get(1 );        cache.get(3 );        cache.get(4 );        
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 class  LRUCache   {         class  Node   {         int  key;         int  value;         Node before;         Node after;     }          private  HashMap cache = new  HashMap();            private  int  capacity;          private  Node head, tail;     public  LRUCache (int  capacity)   {         this .capacity = capacity;         head = new  Node();         head.before = null ;         tail = new  Node();         tail.after = null ;         head.after = tail;         tail.before = head;     }          public  int  get (int  key)   {         Node node = cache.get(key);         if  (node == null ) {             return  -1 ;         }                  moveToHead(node);         return  node.value;     }          private  void  moveToHead (Node node)   {         removeNode(node);         addToHead(node);     }          private  void  removeNode (Node node)   {         Node before = node.before;         Node after = node.after;         before.after = after;         after.before = before;     }          private  void  addToHead (Node node)   {         node.before = head;         node.after = head.after;         head.after.before = node;         head.after = node;     }     public  void  put (int  key, int  value)   {         Node node = cache.get(key);         if  (node == null ) {             Node newNode = new  Node();             newNode.key = key;             newNode.value = value;             cache.put(key, newNode);             addToHead(newNode);             if  (cache.size() > capacity) {                                  Node tail = this .popTail();                 this .cache.remove(tail.key);             }         } else  {             node.value = value;                          moveToHead(node);         }     }          private  Node popTail ()   {         Node res = tail.before;         this .removeNode(res);         return  res;     } } 
 
152. 乘积最大子数组 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
  示例 1:
  输入: [2,3,-2,4]
  输出: 6
  解释: 子数组 [2,3] 有最大乘积 6。
  示例 2:
  输入: [-2,0,-1]
  输出: 0
  解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  Solution   {    public  int  maxProduct (int [] nums)   {         int  max = nums[0 ], min = nums[0 ], result = nums[0 ];                  for  (int  i = 1 ; i < nums.length; i++) {             int  temp = max;                          max = Math.max(Math.max(max * nums[i], min * nums[i]), nums[i]);                          min = Math.min(Math.min(temp * nums[i], min * nums[i]), nums[i]);                          if  (max > result) result = max;         }         return  result;     } } 
 
198. 打家劫舍 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
  示例 1:
  输入: [1,2,3,1]
  输出: 4
  解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。            偷窃到的最高金额 = 1 + 3 = 4 。
  示例 2:
  输入: [2,7,9,3,1]
  输出: 12
  解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。            偷窃到的最高金额 = 2 + 9 + 1 = 12 。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class  Solution   {    public  int  rob (int [] nums)   {         int  len = nums.length;         if (len == 0 )             return  0 ;         int [] dp = new  int [len + 1 ];         dp[0 ] = 0 ;         dp[1 ] = nums[0 ];         for (int  i = 2 ; i <= len; i++) {                          dp[i] = Math.max(dp[i-1 ], dp[i-2 ] + nums[i-1 ]);         }         return  dp[len];     } } 
 
210. 课程表 II 现在你总共有 n 门课需要选,记为 0 到 n-1。在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。
可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。
  示例 1:
  输入: 2, [[1,0]] 
  输出: [0,1]
  解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。
  示例 2:
  输入: 4, [[1,0],[2,0],[3,1],[3,2]]
  输出: [0,1,2,3] or [0,2,1,3]
  解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3] 。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class  Solution   {    public  int [] findOrder(int  numCourses, int [][] prerequisites) {                  if  (numCourses == 0 ) return  new  int [0 ];                  int [] inDegrees = new  int [numCourses];                  for  (int [] p : prerequisites) {              inDegrees[p[0 ]]++;         }         Queue queue = new  LinkedList<>();                   for  (int  i = 0 ; i < inDegrees.length; i++) {             if  (inDegrees[i] == 0 ) queue.offer(i);         }                  int  count = 0 ;                  int [] res = new  int [numCourses];                  while  (!queue.isEmpty()){                          int  curr = queue.poll();             res[count++] = curr;             for  (int [] p : prerequisites) {                                  if  (p[1 ] == curr){                     inDegrees[p[0 ]]--;                                          if  (inDegrees[p[0 ]] == 0 ) queue.offer(p[0 ]);                 }             }         }                  if  (count == numCourses) return  res;                  return  new  int [0 ];     } } 
 
287. 寻找重复数 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
  示例 1:
  输入: [1,3,4,2,2]
  输出: 2
  示例 2:
  输入: [3,1,3,4,2]
  输出: 3
  说明:
不能更改原数组(假设数组是只读的)。 
只能使用额外的 O(1) 的空间。 
时间复杂度小于 O(n2) 。 
数组中只有一个重复的数字,但它可能不止重复出现一次。 
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  Solution   {    public  int  findDuplicate (int [] nums)   {         if (nums == null  || nums.length == 0 ){             return  0 ;         }         Map map = new  HashMap<>();          for (int  i = 0 ; i < nums.length; i++){             if  (map.get(nums[i]) == null ){                 map.put(nums[i],1 );             } else  {                return  nums[i];             }         }         return  0 ;     } } 
 
394. 字符串解码 给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
  示例:
  s = “3[a]2[bc]”, 返回 “aaabcbc”.
  s = “3[a2[c]]”, 返回 “accaccacc”.
  s = “2[abc]3[cd]ef”, 返回 “abcabccdcdcdef”.
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class  Solution   {    public  String decodeString (String s)   {         if (s == null  || s.length() == 0 ){             return  "" ;         }         StringBuilder sb = new  StringBuilder();         while  (s.contains("[" )) {                                       int  startEqual = 0 , endEqual = 0 ;             for  (int  i = 0 ; i < s.length(); i++) {                 if  (s.charAt(i) == '[' ) {                     startEqual = i;                 }                 if  (s.charAt(i) == ']' ) {                     endEqual = i;                      break ;                 }             }                          String sub = s.substring(startEqual + 1 , endEqual);                          int  numIndex = startEqual - 1 ;             while  (numIndex >= 0  && Character.isDigit(s.charAt(numIndex))){                 numIndex--;             }                                                    int  times = Integer.parseInt(s.substring(numIndex + 1 , startEqual));                          sb.append(s, 0 , numIndex + 1 );             while  (times-- > 0 ){                 sb.append(sub);             }                                           sb.append(s, endEqual + 1 , s.length());             s = sb.toString();             sb = new  StringBuilder();         }         return  s;     } } 
 
402. 移掉K位数字 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意:
num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
  示例 1 :
  输入: num = “1432219”, k = 3
  输出: “1219”
  解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
  示例 2 :
  输入: num = “10200”, k = 1
  输出: “200”
  解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
  示例 3 :
  输入: num = “10”, k = 2
  输出: “0”
  解释: 从原数字移除所有的数字,剩余为空就是0。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class  Solution   {    public  String removeKdigits (String num, int  k)   {         if  (num.length() == k) {             return  "0" ;         }          StringBuilder s = new  StringBuilder(num);                  for  (int  i = 0 ; i < k; i++) {             int  idx = 0 ;                          for  (int  j = 1 ; j < s.length() && s.charAt(j) >= s.charAt(j - 1 ); j++) {                 idx = j;             }                          s.delete(idx, idx + 1 );                          while  (s.length() > 1  && s.charAt(0 ) == '0' ){                 s.delete(0 , 1 );             }         }         return  s.toString();     } } 
 
680. 验证回文字符串 Ⅱ 给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
  示例 1:
  输入: “aba”
  输出: True
  示例 2:
  输入: “abca”
  输出: True
  解释: 你可以删除c字符。
  注意:
  字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class  Solution   {    char [] array;     public  boolean  validPalindrome (String s)   {                  array = s.toCharArray();                  for  (int  low = 0 , high = array.length - 1 ; low < high; low++, high--){             if  (array[low] != array[high]){                 return  isSub(low + 1 , high) || isSub(low, high - 1 );             }         }                  return  true ;     }     public  boolean  isSub (int  low, int  high)  {         while (low < high){             if  (array[low++] != array[high--]){                 return  false ;             }         }         return  true ;     } } 
 
974. 和可被 K 整除的子数组 给定一个整数数组 A,返回其中元素之和可被 K 整除的(连续、非空)子数组的数目。
  示例:
  输入:A = [4,5,0,-2,-3,1], K = 5
  输出:7
  解释:
  有 7 个子数组满足其元素之和可被 K = 5 整除:
  [4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]
  提示:
  1 <= A.length <= 30000
  -10000 <= A[i] <= 10000
  2 <= K <= 10000
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  Solution   {    public  int  subarraysDivByK (int [] A, int  K)   {         int  N = A.length, sum = 0 , ans = 0 ;         int [] map = new  int [K];         map[0 ] = 1 ;         for  (int  i = 1 ; i <= N; i++) {                          sum = sum + A[i-1 ];                           int  key = (sum % K + K) % K;             ans += map[key];             map[key]++;         }         return  ans;     } }