• 九章算法


    1  BST迭代器

    注意点:1. 实际就是中序遍历的非递归写法,迭代器就是要用Stack存储数据,不过把不同的模块功能进行了分割,而不是一次完成中序遍历;

        2. 可以把添加到Stack单独抽取成一个函数,面向对象,更容易理解。

    http://www.lintcode.com/en/problem/binary-search-tree-iterator/#

     1  public class BSTIterator {
     2     //@param root: The root of binary tree.
     3     TreeNode next = null;
     4     Stack<TreeNode> stack = new Stack<TreeNode>();
     5     public BSTIterator(TreeNode root) {
     6         // write your code here
     7         next = root;
     8     }
     9 
    10     //@return: True if there has next node, or false
    11     public boolean hasNext() {
    12         // write your code here
    13         while(next != null) {
    14             stack.push(next);
    15             next = next.left;
    16         }
    17         if(stack.isEmpty()) return false;
    18         return true;
    19     }
    20     
    21     //@return: return next node
    22     public TreeNode next() {
    23         // write your code here
    24         if(!hasNext()) return null;
    25         TreeNode cur = stack.pop();
    26         if(cur.right == null) next = null;
    27         else next = cur.right;
    28         return cur;
    29     }
    30 }
    View Code

    2 二叉查找树中搜索

    注意点:见代码

        不一定要完全遍历二叉树,可以在遍历前判断下来减少遍历的量。

        if(root.val > k1)  helper(root.left, result, k1, k2);

    http://www.lintcode.com/zh-cn/problem/search-range-in-binary-search-tree/

     1 //可以定义一个 ArrayList<Integer> result的成员变量,这样helper中就不需要resul作为参数一直传递添加了。
     2   public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) {
     3      ArrayList<Integer> result = new ArrayList<Integer> ();
     4      helper(root, result, k1, k2);
     5      return result;
     6  }
     7  private void helper(TreeNode root, ArrayList<Integer>  result, int k1, int k2) {
     8      if(root == null) return;
     9      helper(root.left, result, k1, k2);
    10      if(root.val >= k1 && root.val <= k2) result.add(root.val);
    11      helper(root.right, result, k1, k2);
    12      return;
    13  }
    View Code

    3 二叉树中插入结点

    http://www.lintcode.com/en/problem/insert-node-in-a-binary-search-tree/

    注意点:非递归的插入方式

     1  public TreeNode insertNode(TreeNode root, TreeNode node) {
     2         // write your code here
     3         if(root == null) {
     4             root = node;
     5             return root;
     6         }
     7         if(root.val <= node.val) {
     8             root.right = insertNode(root.right, node);
     9             
    10         } else {
    11             root.left = insertNode(root.left, node);
    12         }
    13         return root;
    14     }
    15 //非递归
    16  public TreeNode insertNode(TreeNode root, TreeNode node) {
    17         // write your code here
    18         if(root == null) {
    19             root = node;
    20             return root;
    21         }
    22         TreeNode last = null, temp = root;
    23         while(temp != null) {
    24             last = temp;
    25             if(temp.val <= node.val) temp = temp.right;
    26             else temp = temp.left;
    27         }
    28         if(last != null) { //可以不判断,last不可能为null
    29             if(last.val <= node.val) last.right = node;
    30             else last.left = node;
    31         }
    32         return root;
    33     }
    34     
    View Code

    4  二叉树删除结点

    http://www.lintcode.com/en/problem/remove-node-in-binary-search-tree/

    注意点:见代码

        结点的传递是地址传递,所以将待改变结点的引用传入函数,函数操作后,整个树是会发生变化的。

        待删结点有两个子树的删除方式:

      

     1 public TreeNode removeNode(TreeNode root, int value) {
     2         TreeNode dummy = new TreeNode(0); //dummy的值随便取,反正不输出,为了仅仅是给root设个头
     3         dummy.left = root; 
     4         
     5         TreeNode parent = findNode(dummy, root, value);
     6         TreeNode node; //待删结点
     7         if (parent.left != null && parent.left.val == value) {
     8             node = parent.left;
     9         } else if (parent.right != null && parent.right.val == value) {
    10             node = parent.right;
    11         } else {
    12             return dummy.left ;  //待删结点不存在
    13         }
    14         
    15         deleteNode(parent, node);
    16         
    17         return dummy.left ;
    18     }
    19     
    20     private TreeNode findNode(TreeNode parent, TreeNode node, int value) {  //返回待删结点的父节点,待删的不存在也返回父节点
    21         if (node == null) {
    22             return parent;
    23         }
    24         
    25         if (node.val == value) {
    26             return parent;
    27         }
    28         if (value < node.val) {
    29             return findNode(node, node.left, value);
    30         } else {
    31             return findNode(node, node.right, value);
    32         }
    33     }
    34     
    35     private void deleteNode(TreeNode parent, TreeNode node) {
    36         if (node.right == null) {
    37             if (parent.left == node) {
    38                 parent.left = node.left;
    39             } else {
    40                 parent.right = node.left;
    41             }
    42         } else {
    43             TreeNode temp = node.right;
    44             TreeNode father = node;
    45             
    46             while (temp.left != null) {
    47                 father = temp;
    48                 temp = temp.left;
    49             }
    50             
    51             if (father.left == temp) {
    52                 father.left = temp.right;
    53             } else {
    54                 father.right = temp.right;
    55             }
    56             
    57             if (parent.left == node) {
    58                 parent.left = temp;
    59             } else {
    60                 parent.right = temp;
    61             }
    62             
    63             temp.left = node.left;
    64             temp.right = node.right;
    65         }
    66     }
    View Code

     DP--------------------------------------------------------------------------------------------------------------------------------------------------------------------

    满足下面三个条件之一:
    ● 求最大值最小值
    ● 判断是否可行
    ● 统计方案个数
    则 极有可能 是使用动态规划求解

    序列型dp 递推表达式f[] 里代表着含有0个~length个字符,所以数组的长度定义为length+1;
    区间型dp 递推表达式f[] 里代表着坐标,所以数组的长度定义为length;

    1  数字三角形

    http://www.lintcode.com/zh-cn/problem/triangle/

    疑问: 用HashMap怎么存?编译不通过?????

    注意点:top- down 、down - top、 记忆化搜索

        初始化三角形的顶点和两个侧边

    错误点:

     1 //搜索记忆,查找过的结点不需要再查一次,所以复杂度为O(n * n)
     2 int[][] triangle = null;
     3 int[][] sumMin = null;
     4 int n;
     5 public int minimumTotal(int[][] triangle) {
     6     if(triangle == null || triangle.length == 0 || triangle[0].length == 0) return 0;
     7     this.n = triangle.length;
     8     this.triangle = triangle;
     9     this.sumMin = new int[n][n];
    10     for(int i = 0; i< n; i++) {
    11         for(int j = 0; j < n ; j++) sumMin[i][j] = Math.MAX_VALUE;
    12     }
    13     
    14     return helper(0, 0);
    15 }
    16 private  int helper(int x, int y) {
    17     if(x >= n) return 0;
    18     if(sumMin[x][y] != Math.MAX_VALUE) return sumMin[x][y];
    19     sumMin[x][y] = Math.min(helper(x+1, y),helper(x+1,y+1)) + triangle[x][y];
    20     return  sumMin[x][y];
    21 }
    22 // 同上,用哈希表存查过的结点
    23 int[][] triangle = null;
    24 HashMap<int[], Integer> sumMin = new HashMap<int[], Integer>();
    25 int n;
    26 public int minimumTotal(int[][] triangle) {
    27     if(triangle == null || triangle.length == 0 || triangle[0].length == 0) return 0;
    28     this.n = triangle.length;
    29     this.triangle = triangle;
    30     for(int i = 0; i< n; i++) {
    31         for(int j = 0; j < n ; j++) sumMin[i][j] = Math.MAX_VALUE;
    32     }
    33     
    34     return helper(0, 0);
    35 }
    36 private  int helper(int x, int y) {
    37     if(x >= n) return 0;
    38     if(sumMin.containsKey({x,y})) return sumMin.get({x,y});
    39     int value = Math.min(helper(x+1, y),helper(x+1,y+1)) + triangle[x][y];
    40     sumMin.put({x,y}, value);
    41     return  value;
    42 }
    43 //top - down
    44 public int minimumTotal(int[][] triangle) {
    45     if(triangle == null || triangle.length == 0 || triangle[0].length == 0) return 0;
    46     int row = triangle.length;
    47     for(int i =1; i < row; i++) {
    48         triangle[i][0] +=  triangle[i-1][0];
    49         triangle[i][i] += triangle[i-1][i-1];
    50     }
    51     for(int i = 2; i < row; i++) {
    52         for(int j =1; j < i; j++) {
    53             triangle[i][j] += Math.min(triangle[i-1][j],triangle[i-1][j-1]);
    54         }
    55     }
    56     for(int i = 1; i < row; i++) {
    57         triangle[row-1][0] = Math.min(triangle[row-1][i],triangle[row-1][0]);
    58     }
    59     return triangle[row-1][0];
    60 }
    61 //down - top
    62 public int minimumTotal(int[][] triangle) {
    63     if(triangle == null || triangle.length == 0 || triangle[0].length == 0) return 0;
    64     int row = triangle.length;
    65     for(int i= row -2; i >=0; i--) {
    66         for(int j=0; j<= i; j++)
    67         triangle[i][j] += Math.min(triangle[i+1][j], triangle[i+1][j+1]);
    68     }
    69     return triangle[0][0];
    70 }
    View Code

    2 爬梯子

    http://www.lintcode.com/zh-cn/problem/climbing-stairs/

    注意点:类似斐波那契别超时~

     1 public int climbStairs(int n) { 
     2      if(n == 0) return 1;
     3     a = 1;
     4     b = 1;
     5     for(int i = 2; i <= n; i++) {
     6         int c = a+ b;
     7         c= b;
     8         a = b;
     9     }
    10     return c;
    11  }
    12 //---------------------
    13  public int climbStairs(int n) { 
    14     int[] f = new int[n+1];
    15     if(n == 0) return 1;
    16     f[0] = 1;
    17     f[1] = 1;
    18     for(int i = 2; i <= n; i++) {
    19         f[i] = f[i - 1] + f[i - 2];
    20     }
    21     return f[n];
    22  }
    更新版本1
     1 // 递归调用会超时,因为有重复计算的过程
     2    public int climbStairs(int n) {
     3        if(n == 0) return 1;
     4        if(n == 1) return 1;
     5        return climbStairs(n-2)+climbStairs(n-1);
     6    }
     7  //  加入记忆化搜索,还超时
     8  int[] result = null;
     9    public int climbStairs(int n) {
    10        result = new int[n];
    11        Arrays.fill(result, -1);
    12        if(n == 0) return 1;
    13        if(n == 1) return 1;
    14        result[0] = 1,   result[1] = 1;
    15        return helper(n);
    16    }
    17    private int helper(n) {
    18        if(result[n] != -1) return result[n];
    19        return helper(n-1) + helper(n-2);
    20    }
    21    //
    22     public int climbStairs(int n) {
    23          if(n <=1) return 1;
    24          int last = 1, last_last = 1;
    25          int now = 0;
    26          for(int i=1 ; i< n;i++) {
    27              now = last + last_last;
    28              last_last = last;
    29              last = now;
    30          }
    31          return now;
    32      }
    View Code

    3 跳跃游戏

    http://www.lintcode.com/zh-cn/problem/jump-game/

    注意点:O(N * N)的时间复杂度

    错误点:

     1  //  me
     2    public boolean canJump(int[] A) {
     3         // wirte your code here
     4         if(A == null || A.length == 0) return false;
     5         int n = A.length;
     6         int pos =0;
     7         while(pos <= n -1) {
     8             if(A[pos] >= n - 1 - pos) return true;
     9             else {
    10                 int temp = pos + A[pos];
    11                 while(A[temp] == 0) {
    12                     temp--;
    13                     if(temp <= pos) return false;
    14                 }
    15                 pos = temp;
    16             } 
    17         }
    18         return false;        
    19     }
    20 // greedy
    21 public boolean canJump(int[] A) {
    22     if(A == null || A.length == 0) return false;    
    23     int farthest = A[0];
    24     for(int i = 1; i< A.length; i++) {
    25         if(farthest >= i && farthest < i+ A[i]) {
    26             farthest = i + A[i];
    27         }
    28     }
    29     return farthest>= A.length - 1;
    30 }
    31 //dp
    32     public boolean canJump(int[] A) {
    33     if(A == null || A.length == 0) return false;
    34     boolean[] can = new boolean[A.length];
    35     can[0] = true;
    36     for(int i = 1; i < A.length; i++) {
    37         for(int j = 0; j < i; j++) {
    38             if(can[j] && A[j] + j >= i) {
    39                 can[i] = true;
    40                 break;
    41             }
    42         }
    43     }
    44     return can[A.length - 1];
    45 }
    View Code

    4  跳跃游戏二

    http://www.lintcode.com/zh-cn/problem/jump-game-ii/

    注意点:

    错误点:结果数组没有初始化,数组间的关系没搞清楚

     1 public int jump(int[] A) {
     2         // state
     3         int[] steps = new int[A.length];
     4 
     5         // initialize
     6         steps[0] = 0;
     7         for (int i = 1; i < A.length; i++) {
     8             steps[i] = Integer.MAX_VALUE;
     9         }
    10 
    11         // function
    12         for (int i = 1; i < A.length; i++) {
    13             for (int j = 0; j < i; j++) {
    14                 if (steps[j] != Integer.MAX_VALUE && j + A[j] >= i) {
    15                     //steps[i] = Math.min(steps[i], steps[j] + 1);
    16                     steps[i] = steps[j] + 1;
    17                     break; //贪心
    18                 }
    19             }
    20         }
    21         
    22         // answer
    23         return steps[A.length - 1];
    24     }
    View Code

    5  two Sum

    http://www.lintcode.com/en/problem/two-sum/

    注意点: map里存需要的值和它的角标;

     1 //dp
     2   public int[] twoSum(int[] numbers, int target) {
     3     // write your code here
     4     HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
     5     for(int i = 0 ; i< numbers.length; i++) {
     6         if(map.get(numbers[i]) != null) {
     7             int[] result = {map.get(numbers[i]) + 1, i+1};
     8             return result;
     9         }
    10         // if在前,put在后,一定要这样,先看有没有再放。
    11         map.put(target - numbers[i], i);
    12     }
    13     int[] result = {};
    14     return result;
    15  }
    16 //---------------------------
    17 public int[] twoSum(int[] numbers, int target) {
    18     // write your code here
    19     if(numbers == null || numbers.length <= 1) return null;
    20     for(int i = 0; i< numbers.length - 1; i++) {
    21         for(int j = i+1; j< numbers.length; j++) {
    22             if(numbers[i] == target - numbers[j]) return new int[]{i + 1, j + 1};
    23         }
    24     }
    25     return null;
    26  }
    View Code

     6 k sum   不会

    http://www.lintcode.com/zh-cn/problem/k-sum/

     7 最长上升连续子序列

    http://www.lintcode.com/zh-cn/problem/longest-increasing-continuous-subsequence/

    注意点:

     1 public int longestIncreasingContinuousSubsequence(int[] A) {
     2     if(A == null || A.length == 0) return 0;
     3     int[] result = new int[A.length];
     4     Arrays.fill(result, 1);
     5     int max = 1;
     6     for(int i = 1; i< A.length; i++) {
     7         if(result[i -1] == 1) {
     8             result[i] =2;
     9             if(max < result[i]) max = result[i];
    10             continue;
    11         }
    12         if(A[i-2] < A[i -1] && A[i-1] < A[i] ||
    13         A[i-2] > A[i-1] && A[i-1] > A[i])
    14         result[i] =  result[i- 1]+1;
    15         else result[i] = 2;
    16         if(max < result[i]) max = result[i];
    17     }
    18     return max;
    19 }
    20 //------------------------------------------------------------
    21 public int longestIncreasingContinuousSubsequence(int[] A) {
    22     if(A == null || A.length == 0) return 0;
    23     int max = 1;
    24     int length =1;
    25     for(int i = 1; i < A.length; i++) {
    26         if(A[i] > A[i-1]) length++;
    27         else length=1;
    28         max= Math.max(length, max);
    29     }
    30     for(int i = A.length -2; i >=0; i--) {
    31         if(A[i+1] < A[i]) length++;
    32         else length=1;
    33         max= Math.max(length, max);
    34     }
    35     return max;
    36 }
    View Code

     8 最长连续序列

    http://www.lintcode.com/zh-cn/problem/longest-consecutive-sequence/

    注意点: 求数组中连续序列个数的两种方式: 

           先排序,在求最长的递增序列长度;

           把元素放到set里,之后遍历数组,查找是否包含连续序列,见代码。

     1 public int longestConsecutive(int[] num) {
     2      if(num == null || num.length == 0) return 0;
     3      int[] sortArray = bucketSort(num);
     4      int[] f= new int[sortArray.length];
     5      f[0] = 1;
     6      int maxLen = 1;
     7      for(int i = 1; i < sortArray.length; i++) {
     8          f[i] = 1;
     9          if(sortArray[i] == sortArray[i -1] + 1) {
    10              f[i] = f[i - 1] + 1;
    11          } else if(sortArray[i] == sortArray[i -1]) f[i] = f[i - 1];
    12          if(maxLen < f[i]) maxLen = f[i];
    13      }
    14      return maxLen;
    15  }
    16  private int[] bucketSort(int[] num) {
    17      if(num == null || num.length == 0) return null;
    18      int max = 0, min = 0;
    19      for(int i : num) {
    20          if(max <= i) max = i;
    21          if(min >= i) min = i;
    22      }
    23      long[] bucket = new long[max - min + 1];
    24      for(int i : num) {
    25          //如果min= 3, 4应该放在1的位置
    26          bucket[i - min]++;
    27      }
    28      int[] result = new int[num.length];
    29      int i = 0;
    30      for(int j = 0; j < bucket.length; j++) {
    31         if(bucket[j] == 0) continue;
    32         while(bucket[j] != 0) {
    33             result[i] = j + min;
    34             bucket[j] -= 1;
    35             i++;
    36         }        
    37      }
    38      return result;
    39  }
    先进行桶排序,有NegativeArraySizeException
     1  public int longestConsecutive(int[] num) {
     2      if(num == null || num.length == 0) return 0;
     3      Set<Integer> set = new HashSet<Integer>();
     4      for(int i : num) set.add(i);
     5      int max = 0;
     6      for(int i = 0; i< num.length; i++) {
     7          int down = num[i];
     8          while(set.contains(down)) {
     9              set.remove(down);
    10              down--;
    11          }
    12          int up = num[i] + 1;
    13          while(set.contains(up)) {
    14              set.remove(up);
    15              up++;
    16          }
    17          max = Math.max(max, up-down - 1);
    18      }
    19      return max;
    20  }
    View Code
     1 public int longestConsecutive(int[] num) {
     2     if(num == null || num.length == 0) return 0;
     3     int max = 1;
     4     Arrays.sort(num);
     5     HashMap<Integer,Integer> map = new HashMap<Integer, Integer>();
     6     for(int i = 0; i < num.length; i++) {
     7         if(map.get(num[i]) != null) {
     8             map.put(num[i] + 1, map.get(num[i]) + 1);
     9         } else     map.put(num[i] + 1, 1);
    10         max = Math.max(max, map.get(num[i] + 1));
    11     }
    12     return max;
    13 }
    14 //用set存放,while循环找顺序序列,而不需要提前排序
    15  public int longestConsecutive(int[] num) {
    16     if(num == null || num.length == 0) return 0;
    17     HashSet<Integer> set = new HashSet<Integer>();
    18     for(int i = 0; i < num.length; i++) {
    19         set.add(num[i]);
    20     }
    21     int max = 1;
    22     for(int i=0;i< num.length; i++) {
    23         int down = num[i] - 1;
    24         while(set.contains(down)) {
    25             set.remove(down);
    26             down--;
    27         }
    28         int up = num[i] + 1;
    29         while(set.contains(up)) {
    30             set.remove(up);
    31             up++;
    32         }
    33         max = Math.max(max, up - down -1);
    34     }
    35     return max;
    36 }
    View Code

     9 最大子数组  部分答案看不懂,还是不懂~~~

    http://www.lintcode.com/zh-cn/problem/maximum-subarray/

    注意点:

     1 public int maxSubArray(int[] nums) {
     2     //错误点: 没有考虑到 4,-1,2,1 这种情况,应该是6,目前结果时4.
     3     if(nums == null || nums.length == 0) return 0;
     4     int[] f = new int[nums.length];
     5     int max = f[0] =  nums[0];
     6     for(int i = 1; i < nums.length; i++) {
     7         if(nums[i] >= 0) {
     8             if(f[i - 1] >=0) f[i] = f[i-1] + nums[i];
     9             else f[i] = nums[i];
    10         } else {
    11             if(f[i - 1] < nums[i]) f[i] = nums[i];
    12             else f[i] = nums[i];
    13             
    14         }
    15         max = Math.max(max, f[i]);
    16     }
    17     return max;
    18 }
    19 public int maxSubArray(int[] nums) {
    20     if(nums == null || nums.length == 0) return 0;
    21     int max = nums[0], sum = 0;
    22     for(int i = 0; i < nums.length; i++) {
    23         sum +=nums[i];
    24         max = Math.max(sum, max);
    25         sum = Math.max(sum, 0);
    26     }
    27     return max;
    28 }
    1
     1  public int maxSubArray(int[] nums) {
     2     int max = Integer.MIN_VALUE, sum = 0;
     3     if(nums == null || nums.length  ==0) return 0;
     4     for(int i =0; i < nums.length; i++) {
     5         sum += nums[i];
     6         max = Math.max(sum, max); //用max记录每次sum后现阶段遇到的最大sum和。
     7         sum = Math.max(0, sum);  //每次sum的和一定要大于0,否则之前sum的数字就不要了。
     8     }
     9     return max;
    10  }
    11  //---------------------------------------------------------------
    12   public int maxSubArray(int[] nums) {
    13     int max = Integer.MIN_VALUE, sum = 0;
    14     if(nums == null || nums.length  ==0) return 0;
    15     int[] partMax = new int[nums.length];
    16     int[] globalMax = new int[nums.length];
    17     partMax[0] = globalMax[0] = nums[0];
    18     
    19     for(int i = 1; i < nums.length; i++) {
    20         partMax[i] = Math.max(partMax[i - 1] + nums[i], nums[i]);
    21         globalMax = Math.max(partMax[i], globalMax[i-1]);
    22     }
    23     return globalMax[nums.length - 1];
    24 }
    View Code

     10 分割回文串2

    http://www.lintcode.com/zh-cn/problem/palindrome-partitioning-ii/#

    注意点:

     1 private boolean[][] getInstance(String s) {
     2     boolean[][] str = new boolean[s.length()][s.length()];
     3     for(int i = 0; i < s.length(); i++) {
     4         str[i][i] = true;
     5     }
     6     for(int i = 0; i < s.length() - 1; i++) {
     7         str[i][i+1] = s.charAt(i) == s.charAt(i+1);
     8     }
     9     for(int len = 2;len <s.length(); len++) {
    10         for(int i = 0; i + len < s.length(); i++) {
    11             str[i][i+len] = str[i + 1][i+len -1] && s.charAt(i) == s.charAt(i+len);
    12         }
    13     }
    14     return str;
    15 }
    16 public int minCut(String s) {
    17     if(s==null || s.length() ==0) return 0;
    18     boolean[][] str = getInstance(s);
    19     int[] f = new int[s.length() + 1];
    20     for(int i = 0; i < f.length; i++) {
    21         f[i] = i - 1;
    22     }
    23     for(int i= 1; i <= s.length(); i++) {
    24         for(int j = 0; j < i; j++) {
    25             if(str[j][i-1]) {
    26                 f[i]= Math.min(f[i], f[j] + 1);
    27             }
    28         }
    29     }
    30     return f[f.length -1];
    31 }
    5-24 简化写法
     1 for(int i = 0; i<f.length; i++) {  
     2         f[i] = i - 1;  //i长度的字符串,最多分割i-1刀可以构成回文串,设为Integer.MAX_VALUE也行,关键是f[0]=-1,f[1]=0
     3     }
     4     for(int i = 1; i <= s.length(); i++) { //长度为i的字符串
     5         for(int j = 0; j< i; j++) {              //两个子串: 0~j-1, j~i-1,判断是否是回文串。
     6             if(str[j][i-1]) {
     7                 f[i] = Math.min(f[i], f[j] + 1);  //f[j]已经在之前求出来了,表示0~j-1这j个字符至少分几刀可以形成回文串
     8             }
     9         }
    10     }
    部分解释
     1   private boolean isPalindrome(String s, int start, int end) {
     2     for(int i = start, j = end; i < j; i++,j--) {
     3         if(s.charAt(i) != s.charAt(j)) return false;        
     4     }
     5     return true;
     6 }
     7 private boolean[][] getPalindromeInstance(String s) {
     8     boolean[][] str = new boolean[s.length()][s.length()];
     9     for(int i = 0; i<s.length(); i++) {
    10         str[i][i] = true;
    11     }
    12     for(int i = 0; i<s.length() - 1; i++) {
    13         str[i][i+1] = isPalindrome(s, i, i+1);
    14     }
    15     for(int len = 2; len < s.length(); len++) {  //长度是len+1的子串
    16         for(int i = 0; i + len < s.length(); i++) {    //len+i代表尾角标位置
    17             str[i][i+len] = isPalindrome(s, i + 1, i+len - 1) && s.charAt(i) == s.charAt(i+len);
    18         }
    19     }
    20     return str;
    21 }
    22 public int minCut(String s) {
    23      if(s==null || s.length() == 0) return 0;
    24      boolean[][] str = getPalindromeInstance(s);
    25      
    26      int[] f = new int[s.length() + 1];
    27      for(int i = 0; i < f.length; i++) {  //长度为i的字符串最多分割i-1次就可以都是回文串,也可以将f[i]设为Integer.MAX_VALUE;
    28          f[i] = i - 1;
    29      }
    30      for(int i = 1; i<= s.length(); i++) {//i个字符构成回文串
    31         for(int j = 0; j < i; j++) {
    32             if(str[j][i -1]) {
    33                 f[i] = Math.min(f[i],f[j] + 1);
    34             }
    35         }
    36      }
    37      return f[f.length - 1];
    38 }
    View Code

     11  单词分割

    http://www.lintcode.com/problem/word-break

     1 public boolean wordBreak(String s, Set<String> dict) {
     2     if(s == null || s.length() == 0) return true;
     3     if(dict == null ||dict.size() == 0) return false;
     4     int wordLen = 0;
     5     for(String s1 : dict) {
     6         wordLen = Math.max(wordLen, s1.length());
     7     }
     8     boolean f[] = new boolean[s.length() + 1];
     9     f[0] = true;
    10     for(int i = 1; i <= s.length(); i++) {   //i表示包含i个单词,j表示最后一个单词的长度
    11         f[i] = false;
    12         //0~i-1   0~i-j-1,i-j~i-1
    13         for(int j=1;j<=wordLen && j<=i; j++) {
    14             if(f[i-j]) {
    15                 if(dick.contains(s.subString(i-j, i-1))) {
    16                     f[i] = true;
    17                     break;
    18                 }
    19             }
    20         }
    21     }
    22     return f[f.length - 1];
    23 }
    update 1
     1 public boolean wordBreak(String s, Set<String> dict) {
     2     if(s == null || dict == null) return false;
     3     if(dict.size() == 0) {
     4         if(s.length() == 0 ) return true;
     5         return false;
     6     }
     7     int maxLen = 0;
     8     for(String s1 : dict) {
     9         maxLen = Math.max(s1.length(), maxLen);
    10     }
    11     boolean[] canBreak = new boolean[s.length() + 1];
    12     canBreak[0] = true;
    13     for(int i = 1; i <= s.length(); i++) {
    14         canBreak[i] = false;
    15         for(int lastWordLen = 1; lastWordLen <=i && lastWordLen <= maxLen; lastWordLen++) {
    16             if(canBreak[i - lastWordLen]) {    //最后一个单词的下标是 [i - lastWordLen, i) 左开右闭,包含的字符个数为lastWordLen
    17                 String word = s.substring(i - lastWordLen, i); 
    18                 if(dict.contains(word)) {
    19                     canBreak[i] = true;
    20                     break;
    21                 }
    22             }
    23         }
    24     }
    25     return canBreak[s.length()];
    26 }
    View Code

     12 最长公共子序列  LCS

    http://www.lintcode.com/zh-cn/problem/longest-common-subsequence/#

     1 public int longestCommonSubsequence(String A, String B) {
     2     if(A == null || B == null || A.length() == 0 || B.length() == 0) {
     3         return 0;
     4     }
     5     int m = A.length(), n = B.length();
     6     int[][] f = new int[m+1][n+1];
     7     for(int i = 1; i <=m; i++) {
     8         f[i][0] = 0;
     9     }
    10     for(int i = 0; i <=n; i++) {
    11         f[0][i] = 0;
    12     }
    13     for(int i = 1; i<=m; i++) {
    14         for(int j =1; j<=n; j++) {
    15             if(A.charAt(i-1) == B.charAt(j-1)) {
    16                 f[i][j] = f[i-1][j-1]+1;
    17             } else {
    18                 f[i][j] = Math.max(f[i][j-1],f[i-1][j]);
    19             }
    20         }
    21     }
    22     return f[m][n];
    23 }
    update 1
     1     public int longestCommonSubsequence(String A, String B) {
     2     if(A == null || B == null || A.length() == 0 || B.length() == 0) return 0;
     3     int[][] lcs = new int[A.length() + 1][B.length() + 1];
     4     for(int i = 0; i <= A.length(); i++) {
     5         lcs[i][0] = 0;
     6     }
     7     for(int j = 0; j <= B.length(); j++) {
     8         lcs[0][j] = 0;
     9     }
    10     for(int i = 1; i <= A.length(); i++) {
    11         for(int j = 1; j <= B.length(); j++) {
    12             if(A.charAt(i-1) == B.charAt(j-1)) {
    13                 lcs[i][j] =  Math.max(lcs[i - 1][j - 1]+1, Math.max(lcs[i - 1][j], lcs[i][j - 1]));  //只写lcs[]][]+1即可,不用判断的
    14             } else {
    15                 lcs[i][j] =  Math.max(lcs[i - 1][j - 1]+0, Math.max(lcs[i - 1][j], lcs[i][j - 1]));
    16             }
    17         }
    18     }
    19     return lcs[A.length()][B.length()];
    20 }
    View Code

     13  最长公共子串

    http://www.lintcode.com/zh-cn/problem/longest-common-substring/#

    问题: contains复杂度O(n)???

    注意点:

    错误点: f[i][j]的含义搞不太懂,想一想递归关系之间的具体实现过程。在循环过程中,公共子串中的每一个字符都会作为最后一个字符去进行比较。

     1 public int longestCommonSubstring(String A, String B) {
     2     if(A == null || B == null || A.length() == 0 || B.length() == 0) return 0;
     3     int max = 0;
     4     for(int i = 0; i < A.length(); i++) {
     5         for(int j= i + 1; j <= A.length(); j++) {
     6             if(B.contains(A.substring(i,j))) max = Math.max(max, j- i);
     7         }
     8     }
     9     return max;                //O(n * n * n)
    10  }
    11 //----------------------------------------------------
    12 public int longestCommonSubstring(String A, String B) {
    13     if(A == null || B == null || A.length() == 0 || B.length() == 0) return 0;
    14     
    15     int[][] lcs = new int[A.length() + 1][B.length() + 1];
    16     for(int i = 1; i <= A.length(); i++) {
    17         for(int j = 1; j <= B.length(); j++) {
    18             if(A.charAt(i-1) == B.charAt(j-1)) {
    19                 lcs[i][j] = lcs[i - 1][j - 1]+1;
    20             } else {
    21                 lcs[i][j] =  0;
    22             }
    23         }
    24     }
    25     
    26     int max = 0;    
    27     for(int i = 1; i <= A.length(); i++) {
    28         for(int j = 1; j <= B.length(); j++) {
    29             max = Math.max(max, lcs[i][j]);
    30         }
    31     }
    32     return max;
    33 }
    View Code

     14 编辑距离

    http://www.lintcode.com/zh-cn/problem/edit-distance/#

     1  // 为什么要死记公式啊,先求lcs再去匹配一致,考虑并不周全     abc     cab  
     2  public int minDistance(String word1, String word2) {
     3     if(word1 == null || word2 == null) {
     4         if(word1 != null) return word1.length();
     5         if(word2 != null) return word2.length();
     6         return 0;
     7     }
     8     int[][] lcs = new int[word1.length() + 1][word2.length() + 1];
     9     for(int i = 1; i <= word1.length(); i++) {
    10         for(int j = 1; j <= word2.length(); j++) {
    11             if(word1.charAt(i-1) == word2.charAt(j-1)) {
    12                 lcs[i][j] = lcs[i - 1][j - 1]+1;
    13             } else {
    14                 lcs[i][j] =  0;
    15             }
    16         }
    17     }
    18     int max = 0;    
    19     for(int i = 1; i <= word1.length(); i++) {
    20         for(int j = 1; j <= word2.length(); j++) {
    21             max = Math.max(max, lcs[i][j]);
    22         }
    23     }
    24     return Math.max(word1.length()-max, word2.length() - max);
    25 }
    26 //----------------------
    27  public int minDistance(String word1, String word2) {
    28     if(word1 == null || word2 == null) {
    29         if(word1 != null) return word1.length();
    30         if(word2 != null) return word2.length();
    31         return 0;
    32     }
    33     int[][] f =  new int[word1.length() + 1][word2.length() + 1];
    34     for(int i = 0; i <= word1.length(); i++) f[i][0] = i;
    35     for(int j = 0; j <= word2.length(); j++) f[0][j] = j;
    36     
    37     for(int i = 1; i <=word1.length(); i++) {
    38         for(int j = 1; j <= word2.length(); j++) {
    39             if(word1.charAt(i - 1) == word2.charAt(j - 1)) {
    40                 f[i][j] = Math.min(Math.min(f[i-1][j] + 1, f[i][j-1]+1),f[i- 1][j - 1]);
    41             } else {
    42                 f[i][j] = Math.min(Math.min(f[i-1][j] + 1, f[i][j-1]+1),f[i- 1][j - 1] + 1);
    43             }
    44         }
    45     }
    46     return f[word1.length()][word2.length()];
    47  }
    View Code

    链表----------------------------------------------------------------------------------------

    注意事项: 调用node.next时,一定要确保node非null,否则空指针异常。

         链表的head 和head.next是否为空先判断下,类似二叉树root要单独拿出来考虑一样。

     1 链表的基本操作
     2 1. Insert a Node in Sorted List
     3 2. Remove a Node from Linked List
     4 3. Reverse a Linked List
     5 4. Merge Two Linked Lists
     6 5. Middle of a Linked List
     7 
     8 1.  // 最简单的方法
     9     private ListNode reverse(ListNode head) {
    10         if(head == null || head.next == null) return head;
    11         ListNode prev = null;
    12         while(head!= null ) {
    13             ListNode temp = head.next;
    14             head.next = prev;
    15             prev = head;
    16             head = temp;
    17         }
    18         return prev;
    19     }
    20     //另一种写法
    21  private ListNode reverse(ListNode head) {
    22      if(head == null || head.next == null) return head;
    23      ListNode tail = head;
    24      ListNode next =tail.next;
    25      while(next != null) {
    26          ListNode temp = next.next;
    27          next.next =tail;
    28         tail = next;
    29         next =temp;
    30      }        
    31      head =tail;
    32      tail.next = null;
    33      return head;
    34  }
    35 4. private ListNode merge(ListNode left, ListNode right) {
    36     ListNode dummy = new ListNode(0), tail = dummy;
    37     while(left != null && right != null) {
    38         tail.next = left;
    39         left = left.next;
    40         tail = tail.next;
    41         tail.next = right;
    42         right.next = right;
    43         tail = tail.next;
    44     }
    45     if(left != null) tail.next = left;
    46     else tail.next = right;
    47     return dummy.next;
    48 }
    49 5.   快慢指针
    50     private ListNode getMid(ListNode head) {}
    51      //12345  要找到3
    52      if(head == null || head.next == null) return head;
    53      ListNode slow = head, fast = head;
    54      while(fast.next != null && fast.next.next != null) {
    55          slow = slow.next;
    56          fast = fast.next.next;
    57      }
    58      return slow;
    59     //查找倒数第n个结点
    60     private ListNode find(ListNode head) {
    61           ListNode slow = head, fast = head;
    62     // 1 2 3 4 5  找4,倒数第2个,需要在fast走第二步的时候,slow开始走第一步
    63     int i = 0;
    64     while(fast.next != null) {
    65         i++;
    66         fast = fast.next;
    67         if(i < 2) coutinue;
    68         slow = slow.next;
    69     }
    70     return slow;
    71     }
    链表基本操作

    1  删除排序链表2

    http://www.lintcode.com/zh-cn/problem/remove-duplicates-from-sorted-list-ii/

     1 //----------------运行超时
     2   public static ListNode deleteDuplicates(ListNode head) {
     3         // write your code here
     4         if(head == null || head.next == null) return head;
     5         ListNode prev = null;
     6         ListNode curr = head;
     7         Map<ListNode,Integer> map = new HashMap<ListNode,Integer>();
     8         int value = 0;
     9         while(curr != null) {
    10             if(map.get(curr) != null) {
    11                 map.put(curr,map.get(curr) + 1);
    12             } else {
    13                 map.put(curr,1);
    14             }
    15         }
    16         prev.next = head;
    17         curr = head;
    18         ListNode currNext = curr.next;
    19         while(currNext != null) {
    20             if(map.get(currNext) != 1) {
    21                 curr = currNext;
    22                 currNext.next = currNext.next;
    23             }
    24         }
    25         return prev.next;
    26     }
    27 //--------------------------------------------------
    28  public static ListNode deleteDuplicates(ListNode head) {
    29      if(head == null || head.next == null) return head;
    30      ListNode dummy = new ListNode(0);
    31      dummy.next = head;
    32      //只要不用next操作,引用再怎么换也不会影响链表。
    33      head = dummy;
    34      while(head.next != null && head.next.next != null) {
    35          if(head.next.val == head.next.next.val) {
    36              int val = head.next.val;
    37              while(head.next != null && head.next.val == val) {
    38                  head.next = head.next.next;
    39              }
    40          } else {
    41              head = head.next;
    42          }
    43      }
    44      return dummy.next;
    45  }
    View Code

    2   删除排序链表

    http://www.lintcode.com/zh-cn/problem/remove-duplicates-from-sorted-list/#

    注意点:引入dummy的目的是为了不用将头结点删除与否分情况讨论。这里头结点肯定不用删除,所以可以不引入dummy。

                也可以沿用删除链表2的解法,稍微改改。

     1  public static ListNode deleteDuplicates(ListNode head) { 
     2         // write your code here
     3         if(head == null || head.next == null) return head;
     4         ListNode dummy = new ListNode(0);
     5         dummy.next = head;
     6         head = dummy;
     7         while(head.next != null && head.next.next != null) {
     8             if(head.next.val == head.next.next.val) {
     9                 head.next = head.next.next;
    10             } else head = head.next;
    11         }
    12         return dummy.next;
    13     }  
    View Code

    3  反转链表

    http://www.lintcode.com/zh-cn/problem/reverse-linked-list/

    注意点: 死记解法,四步骤

     1  public ListNode reverse(ListNode head) {
     2         // write your code here
     3        ListNode prev = null;
     4        while(head != null) {
     5            ListNode temp = head.next;
     6            head.next = prev;
     7            prev = head;
     8            head = temp;
     9        }
    10        return prev;
    11     }
    View Code

    4   反转链表2

    http://www.lintcode.com/zh-cn/problem/reverse-linked-list-ii/

    错误点: 第二个for循环里写成了if(nPost.next== null) return null;

    注意点: 第二个for循环里,n~m ,共n-m+1个数字,需要nNode走n-m次,i=m+1时,n移动了一次,所以i最后出了循环需要等于m+n-m = n

     1 public ListNode reverseBetween(ListNode head, int m , int n) {
     2       if(head == null || m >= n) return head;
     3       ListNode dummy = new ListNode(0);
     4       dummy.next = head;
     5       head = dummy;
     6       for (int i = 1; i < m; i++) {
     7           if(head != null) head = head.next;
     8           else return null;
     9       }
    10       ListNode mprev = head;
    11       ListNode mNode = mprev.next;
    12       ListNode nNode = mNode;
    13       ListNode nPost = nNode.next;
    14       for(int i = m; i < n;i++) {
    15           if(nPost == null) return null;
    16           ListNode temp = nPost.next;
    17           nPost.next = nNode;
    18           nNode = nPost;
    19           nPost = temp;
    20       }
    21       mprev.next = nNode;
    22       mNode.next = nPost;
    23       return dummy.next;
    24       
    25   }
    View Code

    5  链表划分

    http://www.lintcode.com/zh-cn/problem/partition-list/

    注意点: 将链表分成两个子链,左链放比指定数小的,右链连比指定数大的,最后再将他们合并。

         leftDummy和rightDummy保持不动,作为头指针,然后从它们的位置发出left和right指针,作为尾指针,依次移动记录当前子链表的最后一个位置。

          头指针.next=头结点,尾指针=尾结点

     1 public ListNode partition(ListNode head, int x) {
     2        if(head == null) return head;
     3        ListNode leftDummy =  new ListNode(0);
     4        ListNode rightDummy =  new ListNode(0);
     5        ListNode left = leftDummy, right = rightDummy;
     6        while(head != null) {
     7            if(head.val < x) {
     8                left.next = head;
     9                left = head;
    10            } else {
    11                right.next = head;
    12                right = head;
    13            }
    14            head = head.next;
    15        }
    16        right.next = null;
    17        left.next = rightDummy.next;
    18        return leftDummy.next;
    19    }
    View Code

     6  链表排序

    http://www.lintcode.com/zh-cn/problem/sort-list/#

    注意点: 

    错误点: sortList(ListNode head) 里if(head == null )而不判断head.next会报错,为啥??????

     1   private ListNode findMid(ListNode head) {
     2         ListNode slow = head, fast = head.next;
     3         while(fast.next != null && fast.next.next != null) {
     4             fast = fast.next.next;
     5             slow = slow.next;
     6         }
     7         return slow;
     8         //  12345   return 2;
     9    }
    10    private ListNode merge(ListNode head1, ListNode head2) {
    11        //dummy是合并后主链表的头,tail是尾。head1或head2中每当有一个结点链入主链,那链入的那个结点就可以
    12        //在原先的链表中删除了,同时把原先的链表的头往后移。因为主链中加入了一个结点,所以主链的tail后移一次。
    13        ListNode dummy = new ListNode(0), tail = dummy;
    14        while(head1 != null && head2 != null) {
    15            if(head1.val < head2.val) {
    16                tail.next = head1;
    17                head1 = head1.next;
    18            } else {
    19                tail.next = head2;
    20                head2 = head2.next;
    21            }
    22            tail = tail.next;
    23        }
    24        //head1或head2有一个都链入主链后,把另一个非空的原先链表在链到主链尾部
    25        //(这时原先链表中的后面位置的结点并没有进行排序。)
    26        //最后返回的结果只是将head1或者head2进行排序了。(head1为空,则代表它完成排序了)
    27        //要保证最后都有序,则head1和head2必须先有序。
    28        if(head1 != null) {
    29            tail.next = head1;
    30        } else {
    31            tail.next = head2;
    32        }
    33        return dummy.next;
    34    }
    35    
    36    public ListNode sortList(ListNode head) {
    37        if(head == null || head.next == null) return head;
    38        ListNode mid = findMid(head);
    39        ListNode right = sortList(mid.next);
    40        mid.next = null; 
    41        ListNode left = sortList(head);
    42        return merge(left, right);
    43     }
    merge排序

    7      重排链表

    http://www.lintcode.com/zh-cn/problem/reorder-list/#

     1 public void reorderList(ListNode head) {  
     2        if(head == null || head.next == null) return;
     3        ListNode mid = getMid(head);
     4        ListNode right = reverse(mid.next);
     5        mid.next = null;
     6        head = merge(head, right);        
     7     }
     8     
     9 private ListNode getMid(ListNode head) {}
    10     //12345   15243 要找到3
    11     if(head == null || head.next == null) return head;
    12     ListNode slow = head, fast = head;
    13     while(fast.next != null && fast.next.next != null) {
    14         slow = slow.next;
    15         fast = fast.next.next;
    16     }
    17     return slow;
    18 }
    19 private ListNode reverse(ListNode head) {
    20     if(head == null || head.next == null) return head;
    21     
    22     ListNode prev = null;
    23     while(head!= null ) {
    24         ListNode temp = head.next;
    25         head.next = prev;
    26         prev = head;
    27         head = temp;
    28     }
    29     return prev;
    30 }
    31 private ListNode merge(ListNode left, ListNode right) {
    32     ListNode dummy = new ListNode(0), tail = dummy;
    33     while(left != null && right != null) {
    34         tail.next = left;
    35         left = left.next;
    36         tail = tail.next;
    37         tail.next = right;
    38         right = right.next;
    39         tail = tail.next;
    40     }
    41     if(left != null) tail.next = left;
    42     else tail.next = right;
    43     return dummy.next;
    44 }
    View Code

    8    带环链表

    http://www.lintcode.com/zh-cn/problem/linked-list-cycle-ii/#

    注意点:快慢指针

     1 public ListNode detectCycle(ListNode head) {  
     2     if(head == null || head.next == null) return null;
     3     ListNode slow1 = head, fast = head;
     4     while(fast.next != null && fast.next.next != null) {
     5         slow1= slow1.next;
     6         fast = fast.next.next;
     7         if(slow1 == fast) {
     8             ListNode slow2 = head;
     9             while(true) {
    10                 if(slow1 == slow2) return slow1;
    11                 slow2 = slow2.next;
    12                 slow1 = slow1.next;
    13             }
    14         }
    15     }
    16     return null;
    17 }
    View Code

     9  旋转链表

    http://www.lintcode.com/zh-cn/problem/rotate-list/#

     1  public ListNode rotateRight(ListNode head, int k) {
     2         if(head == null || head.next == null || k == 0) return head;
     3         int len = 0;
     4         ListNode temp = head;
     5         while( temp != null ) {
     6             len++;
     7             temp = temp.next;
     8         }
     9         k = k % len;
    10         if(k == 0) return head;
    11         ListNode tail= head;
    12         int i = 1;
    13         while( len - k != i) {
    14             i++;
    15             tail = tail.next;
    16         }
    17         ListNode newHead = tail.next, temp1 = newHead;
    18         tail.next = null;
    19         while(temp1.next != null) {
    20             temp1 = temp1.next;
    21         }
    22         temp1.next = head;
    23         return newHead;
    24     }
    25    //----------------------------------------------------
    26     private int getLength(ListNode head) {
    27         int length = 0;
    28         while (head != null) {
    29             length ++;
    30             head = head.next;
    31         }
    32         return length;
    33     }
    34     
    35     public ListNode rotateRight(ListNode head, int n) {
    36         if (head == null) {
    37             return null;
    38         }
    39         
    40         int length = getLength(head);
    41         n = n % length;
    42         
    43         ListNode dummy = new ListNode(0);
    44         dummy.next = head;
    45         head = dummy;
    46         
    47         ListNode tail = dummy;
    48         //寻找倒数第n个结点(类似快慢指针实现的)
    49         for (int i = 0; i < n; i++) {
    50             head = head.next;
    51         }  
    52         while (head.next != null) {
    53             tail = tail.next;
    54             head = head.next;
    55         }
    56         
    57         head.next = dummy.next;
    58         dummy.next = tail.next;
    59         tail.next = null;
    60         return dummy.next;
    61     }
    View Code

     10   合并k个排序链表

    http://www.lintcode.com/zh-cn/problem/merge-k-sorted-lists/

     1 //两两合并----------------------------------------------
     2     public ListNode mergeKLists(List<ListNode> lists) {  
     3         if(lists == null || lists.size() == 0) return null;
     4         
     5         while(lists.size() > 1) {
     6             List<ListNode> newList = new ArrayList<ListNode>();
     7             for(int i = 0; i + 1< lists.size() ; i+=2) {
     8                 ListNode dummy = new ListNode(0);
     9                 dummy.next = mergeTwo(lists.get(i), lists.get(i+1));
    10                 newList.add(dummy.next);
    11             }
    12             if(lists.size() % 2 != 0) newList.add(lists.get(lists.size() - 1));
    13             lists = newList;
    14         }
    15         return lists.get(0);
    16     }
    17     
    18     private ListNode mergeTwo(ListNode node1, ListNode node2) {
    19         ListNode dummy = new ListNode(0), tail = dummy;
    20         while(node1 != null && node2 != null) {
    21             if(node1.val < node2.val) {
    22                 tail.next = node1;
    23                 node1 = node1.next;
    24             } else {
    25                 tail.next = node2;
    26                 node2 = node2.next;
    27             }
    28             tail = tail.next;
    29         }
    30         if(node1 != null) {
    31             tail.next = node1;
    32         } else {
    33             tail.next = node2;
    34         }
    35         return dummy.next;
    36     }
    37     //分治-------------------------------------------------
    38      public ListNode mergeKLists(List<ListNode> lists) {  
    39         if(lists == null || lists.size() == 0) return null;
    40         return mergeHelper(lists, 0, lists.size() - 1);
    41      }
    42      private ListNode mergeHelper(List<ListNode> lists, int start , int end) {
    43          if(start == end) return lists.get(start);
    44          int mid = start + (end - start) / 2;
    45          ListNode left = mergeHelper(lists, start, mid);
    46          ListNode right = mergeHelper(lists, mid+1, end);
    47          return mergeTwo(left, right);
    48      }
    49      
    50     private ListNode mergeTwo(ListNode node1, ListNode node2) {
    51         ListNode dummy = new ListNode(0), tail = dummy;
    52         while(node1 != null && node2 != null) {
    53             if(node1.val < node2.val) {
    54                 tail.next = node1;
    55                 node1 = node1.next;
    56             } else {
    57                 tail.next = node2;
    58                 node2 = node2.next;
    59             }
    60             tail = tail.next;
    61         }
    62         if(node1 != null) {
    63             tail.next = node1;
    64         } else {
    65             tail.next = node2;
    66         }
    67         return dummy.next;
    68     }
    View Code

    11   复制随机指针链表

    http://www.lintcode.com/zh-cn/problem/copy-list-with-random-pointer/#

    注意点:传入head并在另一个函数中操作时,并不会引起传入前的head的变化。 

        见答案,不需要返回值  http://www.jiuzhang.com/solutions/copy-list-with-random-pointer/

     1   public RandomListNode copyRandomList(RandomListNode head) {
     2         if(head == null) return head;
     3          head = insert(head);
     4         RandomListNode dummy = new RandomListNode(0);
     5         dummy.next = head;
     6         while(head != null) {
     7             if(head.random == null) {
     8                 head.next.random = null;
     9             } else {
    10                 head.next.random = head.random.next;
    11             }
    12             head = head.next.next;
    13         }
    14         dummy.next = remove(dummy.next);
    15         return dummy.next;
    16         
    17     }
    18     private RandomListNode insert(RandomListNode head) {
    19         if(head == null) return head;
    20         RandomListNode dummy = new RandomListNode(0);
    21         dummy.next = head;
    22         while(head != null) {
    23             RandomListNode temp = new RandomListNode(head.label);
    24             temp.next = head.next;
    25             head.next = temp;
    26             head = head.next.next;
    27         }
    28         return dummy.next;
    29     }
    30     private RandomListNode remove(RandomListNode head) {
    31         RandomListNode dummy = new RandomListNode(0);
    32         dummy.next = head.next;
    33         while(head.next.next != null) {
    34             RandomListNode temp = head.next.next;
    35             head.next.next = head.next.next.next;
    36             head = temp;
    37         }
    38         return dummy.next;
    39     }
    View Code

     //-----------------------------------------------------------------------------------------------------------------

    Arrays      拿到数组先排序,最快需要nlogn.(快排,归并,堆排),然后看看排序是否有助于问题解决,是否满足复杂度要求。

        数组和的问题,排序后,收尾指针依次中间移动,可以以O(n)的代价,遍历一次就能判断是否满足。

    1    合并排序数组

    注意点:可以从头开始合并,也可以从尾开始合并

    http://www.lintcode.com/zh-cn/problem/merge-sorted-array/

     1  public void mergeSortedArray(int[] A, int m, int[] B, int n) {
     2        int index = m+n-1, i = m - 1, j = n - 1;
     3        while(i >=0 && j >=0) {
     4            if(A[i] > B[j]) {
     5                A[index--] = A[i--]; 
     6               
     7            } else {
     8                A[index--] = B[j--]; 
     9            }
    10        }
    11        while(i >= 0) {
    12            A[index--] = A[i--]; 
    13        } 
    14        while(j >= 0) {
    15            A[index--] = B[j--]; 
    16        }
    17        
    18     }
    View Code

     2  两个排序数组的中位数

    http://www.lintcode.com/zh-cn/problem/median-of-two-sorted-arrays/

    注意点:找中点,就是找第k个数,依次剔除k/2, k/4,......1个数,剩下的就是要找的数。

                  如果k个排序数组找中位数,则二分答案,判断此答案是否位于中间。

    错误点: 需要double,则return时除的时候要 /2.0 而不是  /2

     1 //  A = 2 3 4 5 6 7
     2  //  B = 1
     3  // 找中点,第k = 4大的数,则先去掉 k/2 = 2 个数,之后再从剩下的数中找第k-k/2 = 2大的数。
     4  //                             去2个数时,由于B不包含2个数,所以把A的前2个数去掉,剩下: 4 5 6 7  和 1;  
     5  // 从它们中找第2大的数就是结果。去掉的数不一定非要是A,B中最小的前几个数,只要保证去掉的数比要找的数小,那要找的数的相对位置就不会变。
     6  // 在4 5 6 7  和 1中找第2个大的数时,先去掉1个数,在从剩下的里面找第一个大的数就是结果。所以把1去掉,剩下了4 5 6 7 。这时第1个大的数是4,也就是最后结果。
     7  
     8  public double findMedianSortedArrays(int[] A, int[] B) {
     9     int len = A.length + B.length;
    10     if(len % 2 == 1) return findKth(A, 0, B, 0, len/2+1);
    11     else return (findKth(A, 0, B, 0, len/2) + findKth(A, 0, B, 0, len/2+1)) / 2.0;
    12 }
    13 //函数含义:A数组从AStart角标开始,B从BStart开始,寻找A,B中第k个大的数
    14 private int findKth(int[] A, int AStart, int[] B, int BStart, int k) {
    15     if(AStart >= A.length) return B[BStart + k - 1];
    16     if(BStart >= B.length) return A[AStart + k - 1];
    17     
    18     if(k == 1) {
    19         return Math.min(A[AStart], B[BStart]);
    20     }
    21     
    22     //找第k个,先去掉前k/2个数,AValue和BValue不可能都是MAX_VALUE
    23     int AValue = AStart + k/2 - 1 < A.length ? A[AStart + k/2 - 1] : Integer.MAX_VALUE;
    24     int BValue = BStart + k/2 - 1 < B.length ? B[BStart + k/2 - 1] : Integer.MAX_VALUE;
    25     if(AValue <= BValue) {
    26         //去A的前k/2个数,则去掉后的角标从AStart+k/2开始
    27         return findKth(A, AStart+k/2, B, BStart, k - k/2);  //递归的终止条件是k-k/2=1,一定会走到1,因为1+2+...+ k/2 = k - 1 k是偶数,1+1+2+...+ k/2 = k - 1 k是奇数
    28     } else {
    29         return findKth(A, AStart, B, BStart + k/2, k - k/2);
    30     }
    31 }
    View Code

    3  最大子数组2

    http://www.lintcode.com/zh-cn/problem/maximum-subarray-ii/

    衍生:最小子数组  http://www.lintcode.com/zh-cn/problem/minimum-subarray/#   把数组取反,求出最大子数组,再把结果取反即可。

       最大子数组差   http://www.lintcode.com/zh-cn/problem/maximum-subarray-difference/  左右求出最大最小子数组,因为不许重叠,所以找分割线依次比较。

    错误点:a=1,b=2;错,要写成a=1;b=2;

        int a =1, b = 2; 可以

    注意点:见答案

     1 //最大子数组答案    http://www.lintcode.com/zh-cn/problem/maximum-subarray/   
     2  public int maxSubArray(int[] nums) {
     3     if(nums == null || nums.length == 0) return 0;
     4     int sum = 0, preFixSum = 0, max = Integer.MIN_VALUE;
     5     //理解不了的话,只需要知道这个操作能实现功能就行,死记代码
     6     for(int i = 0; i< nums.length; i++) {
     7         sum+= nums[i];
     8         max = Math.max(max, sum - preFixSum);
     9         preFixSum = Math.min(preFixSum, sum);
    10     }
    11     return max;
    12  }
    13  
    14  public int maxTwoSubArrays(List<Integer> nums) {
    15      if(nums == null || nums.size() <= 1) return 0;
    16      // i是分割线位置,i+1就是分割线之后的第一个位置的坐标
    17      int result = Integer.MIN_VALUE;
    18      for(int i = 0; i < nums.size() - 1; i++) {
    19          int max1 = Integer.MIN_VALUE, max2 = max1;
    20          int sum1 = 0, sum2 = 0, preFix1 = 0, preFix2 = 0;
    21          for(int j = 0; j <=i; j++) {
    22              sum1+=nums.get(j);
    23              max1 = Math.max(max1, sum1 - preFix1);
    24              preFix1 = Math.min(preFix1, sum1);
    25          }
    26          for(int j = i+1; j < nums.size(); j++) {
    27              sum2+=nums.get(j);
    28              max2 = Math.max(max2, sum2 - preFix2);
    29              preFix1 = Math.min(preFix2, sum2);
    30          }
    31          result = Math.max(result, max1+max2);
    32      }
    33      return result;
    34  }
    35  //O(n)---------------------------------------------
    36   public int maxTwoSubArrays(List<Integer> nums) {
    37       int[] left = new int[nums.size()];
    38       int[] right = new int[nums.size()];
    39       int sum = 0, preFixSum = 0, max = Integer.MIN_VALUE;
    40       for(int i = 0; i< nums.size(); i++) {
    41           sum+= nums[i];
    42           max = Math.max(max, sum - preFixSum);
    43           preFixSum = Math.min(preFixSum, sum);
    44           left[i] = max;
    45       }
    46       sum = 0, preFixSum = 0, max = Integer.MIN_VALUE;
    47       for(int i = nums.size() - 1; i >= 0; i--) {
    48           sum+= nums[i];
    49           max = Math.max(max, sum - preFixSum);
    50           preFixSum = Math.min(preFixSum, sum);
    51           right[i] = max;
    52       }
    53       int result = Integer.MIN_VALUE;
    54       for(int i = 0; i < nums.size() - 1; i++) {
    55           result = Math.max(result, left[i] + right[i+1]);
    56       }
    57       return result;
    58   }
    View Code

    4  买卖股票的最佳时机

    http://www.lintcode.com/zh-cn/problem/best-time-to-buy-and-sell-stock/

    http://www.lintcode.com/zh-cn/problem/best-time-to-buy-and-sell-stock-ii/

    http://www.lintcode.com/zh-cn/problem/best-time-to-buy-and-sell-stock-iii/#

     注意点:包含DP

    错误点:  ①profit = Math.max(profit, i - min);

               ②min = Math.min(min, i);            一二前后顺序的区别是是否每一轮至少要包含一个数。此题中盈利的计算,一开始是买入,没有盈利,所以也即一个数都不能包含,

                       所以要先②后①。

     1 //错误逻辑,思路都理不清,代码更写不出来。 
     2  public int maxProfit(int[] prices) {
     3     if(prices == null || prices.length <= 1) return 0;
     4     int profit = 0, min = 0;
     5     for(int i : prices) {
     6         min = Math.min(min, i);
     7         profit + =  i - min;    
     8     }
     9     return profit;
    10 }
    11 // 当天有盈利,代表着当天卖出和前一天买入。连续三天盈利,每隔天的买入卖出正好合下来是三天前买入,三天后卖出的情况。 1    2    3    4
    12 public int maxProfit(int[] prices) {
    13     int profit = 0;
    14     for(int i = 0; i < prices.length- 1; i++) {
    15         int diff = prices[i + 1] - prices[i];
    16         if(diff > 0) profit += diff;
    17     }
    18     return profit;
    19 }
    update1
     1  //-----------------------------------------------------------
     2     //  暴力破解
     3      public int maxProfit(int[] prices) { 
     4         if(prices == null || prices.length == 0) return 0;
     5         int max =0 ;
     6         for(int i = 1; i< prices.length; i++) {
     7             int sum = 0;
     8             for(int j = 0; j < i; j++) {            
     9                 max= Math.max(max, prices[i] - prices[j]);
    10             }            
    11         }
    12         return max;
    13    }
    14  //------------------------------------------------------
    15    public int maxProfit(int[] prices) { 
    16       if(prices == null || prices.length == 0) return 0;
    17       int min = Integer.MAX_VALUE, profit = 0;
    18       for(int i : prices) {
    19           min = Math.min(i, min);   // min = i < min ? i : min;
    20           profit = Math.max(i - min, profit);
    21       }
    22       return profit;
    23    }
    24    
    25 //股票二------------------------------------------
    26 public int maxProfit(int[] prices) {
    27     int profit = 0;
    28     for(int i = 0; i < prices.length- 1; i++) {
    29         int diff = prices[i + 1] - prices[i];
    30         if(diff > 0) profit += diff;
    31     }
    32     return profit;
    33 }
    34 
    35 //股票三-----------------------------------------------
    36 public int maxProfit(int[] prices) {
    37     if (prices == null || prices.length <= 1) {
    38             return 0;
    39         }
    40 
    41     int[] left = int[prices.length];
    42     int[] right = int[prices.length];
    43     
    44     //从左往右看,不依赖于右侧,能卖出的最大利润。通过更新买入的最小值(min)来计算  DP
    45     int min = prices[0], left[0] = 0;
    46     for(int i = 1; i < prices.length; i++) {
    47         min = math.min(min, prices[i]);
    48         left[i] = Math.max(left[i - 1], prices[i] - min);
    49     }
    50     
    51     //从右往左看,不依赖于左侧,能卖出的最大利润。通过更新卖出的最大值(max)来计算
    52     int max = prices[prices.length - 1], right[prices.length - 1] = 0;
    53     for(int i = prices.length -2; i>=0; i--) {
    54         max = Math.max(prices[i], max);
    55         right[i] = Math.max(right[i + 1], max - prices[i]);
    56     }
    57     
    58     //类似分割线,left和right不交叉
    59     int maxProfit = 0;
    60     for(int i = 0; i < prices.length; i++) {
    61         maxProfit = Math.max(maxProfit, left[i] + right[i]);
    62     }
    63     return maxProfit;
    64 }
    View Code

     5  两数和

    http://www.lintcode.com/zh-cn/problem/two-sum/

    衍生: 三数和  http://www.lintcode.com/zh-cn/problem/3sum/ 

        4数    http://www.lintcode.com/zh-cn/problem/4sum/ 

    注意点:时间复杂度的计算:

          排序模块的最优复杂度nlogn,找两数和的复杂度n,所以合并的复杂度是nlogn,即用这种方法的复杂度为nlogn。

          如果放入map中,遍历一次数组,复杂度n,判断map是否包含,n,所以最后合并的复杂度n。

     1 //O(n * n)---------------------------------------------------------------
     2  public int[] twoSum(int[] numbers, int target) { 
     3     if(numbers == null || numbers.length == 0) return new int[]{-1, -1};
     4     for(int i = 0; i < numbers.length - 1; i++) {
     5         for(int j = i +1; j < numbers.length; j++) {
     6             if(numbers[i] + numbers[j] == target) return new int[]{i +1, j+1};
     7         }
     8     }
     9     return new int[]{-1, -1};
    10     
    11  //O(nlogn)--------------------------
    12 public int[] twoSum(int[] numbers, int target) { 
    13     //先排序,获得排序数组nlogn,下面的操作是O(n),最后总体的时间复杂度nlogn.
    14     if(numbers == null || numbers.length <=1) return new int[]{-1, -1};
    15     for(int i = 0, j = numbers.length - 1; i < j;) {
    16         if(numbers[i] + numbers[j] == target) return new int[]{i + 1,j + 1};
    17         else if ( numbers[i] + numbers[j] < target) i++;
    18         else j--;
    19     }
    20     return new int[]{-1, -1};
    21 
    22 }
    23 //O(n)------------------------------
    24 public int[] twoSum(int[] numbers, int target) { 
    25     if(numbers == null || numbers.length == 0) return null;
    26     Map<Integer, Integer> map = new HashMap<Integer, Integer>();
    27     for(int i = 0; i < numbers.length; i++) {    
    28         if(map.containsKey(numbers[i])) {
    29             return new int[] {map.get(numbers[i]) + 1, i+1};
    30         }
    31         map.put(target - numbers[i], i);
    32     }
    33     return null;
    View Code

     6  数组划分 (类似快排)

    http://www.lintcode.com/zh-cn/problem/partition-array/#

    衍生:  http://www.lintcode.com/zh-cn/problem/sort-letters-by-case/        Character.isUpperCase()  

         http://www.lintcode.com/zh-cn/problem/sort-colors/  

         http://www.lintcode.com/zh-cn/problem/sort-colors-ii/    (相当于给定k个不同的数的快排)

     1 //报错,rainb里不设置startColo会排序出问题,所以这种换位的快排操作到底会产生什么结果?----------------------------------------------
     2 public void sortColors2(int[] colors, int k) {
     3      if (colors == null || colors.length == 0) {
     4             return;
     5         }
     6     rainbowSort(colors, 0, colors.length - 1);
     7 
     8 }
     9     
    10 private void rainbowSort(int[] colors, int start, int end) {
    11     if(colors == null || colors.length <= 1) return;
    12     if(start >= end) return;
    13     int mid = start + (end - start) / 2;
    14     int k = colors[mid];
    15     int i = start, j = end;
    16     while(i <= j) {
    17         while(i <=j && colors[i] < k) i++;
    18         while(i <=j && colors[j] >= k) j--;
    19         if(i <= j) {
    20             int temp = colors[i];
    21             colors[i] = colors[j];
    22             colors[j] = temp;
    23             i++;
    24             j--;
    25         }
    26     }
    27     rainbowSort(colors, start, i - 1);
    28     rainbowSort(colors,i + 1, end);
    29 } 
    30 //能用--------------------------------------------------------------------------------- 
    31  public void sortColors2(int[] colors, int k) {
    32      if (colors == null || colors.length == 0) {
    33             return;
    34         }
    35     rainbowSort(colors, 0, colors.length - 1, 1,k);
    36 
    37 }
    38     
    39 private void rainbowSort(int[] colors, int start, int end, int startColor, int endColor) {
    40      if (startColor == endColor) {
    41             return;
    42         }
    43     if(colors == null || colors.length <= 1) return;
    44     if(start >= end) return;
    45     int midColor = (startColor + endColor)/2;
    46     int i = start, j = end;
    47     while(i <= j) {
    48         //为啥??????????????
    49         //这里必须 <= midColor, 不能是<
    50         while(i <=j && colors[i] <=  midColor) i++;
    51         while(i <=j && colors[j] >  midColor) j--;
    52         if(i <= j) {
    53             int temp = colors[i];
    54             colors[i] = colors[j];
    55             colors[j] = temp;
    56             i++;
    57             j--;
    58         }
    59     }
    60     //这里必须是midColor,不能是midColor+1
    61     rainbowSort(colors, start, i, startColor,  midColor);
    62     rainbowSort(colors,i,end,  midColor+1, endColor);
    63 }
    sort color 2

    注意点: 两个指针一首一尾遍历数组        

        死记住程序,条件统一写成 i <= j  :这样返回的 i 始终是第一个大于等于k的位置,也正是题目所求。

        if(i <= j) 调制完顺序后,i++,j--一下,减少下一次while里的操作。

    数组划分
     1   public int partitionArray(int[] nums, int k) {
     2         if(nums == null | nums.length <= 0) return -1;
     3         int i = 0, j = nums.length - 1;
     4         while(i <= j) {
     5             while(nums[i] < k) i++;
     6             while(nums[j] >= k) j--;
     7             if(i <= j) {
     8                 int temp = nums[j];
     9                 nums[j] = nums[i];
    10                 nums[i] = temp;
    11             }
    12         }
    13         return i;
    14    }

     7 最接近零的子数组和

    http://www.lintcode.com/en/problem/subarray-sum-closest/

    问题:最后利用减前缀和求结果的时候,怎么知道这样的结果就离0最近? 难道是因为后一个肯定比前一个大,所以相减的结果一定大于0,最小的那个就是最接近0的?确实是这样。

          -1,-3, -3,-2,1,4,;

     -1位置补0     -1,-3, -3,-2,1,4,   前缀和    -1,-4,-7,-9,-8,-4,排序后:-9,-8,-7,-4,-4,-1。

     子数组一共有O(n * n)个,这里两两相减也就O(n)个,不能全覆盖啊?

    注意点:  实现Comparator比较器接口时,虽然接口中有俩抽象方法,但只需要实现compare方法就行,equals方法不用覆盖。

         此题对应的解法,在数组中有0时,会返回两次0的角标作为返回结果。

    错误点: new int[]{0,1}  ,不要写错new int[2]{}

     1  class Pair {
     2      //记录前几个数的和
     3      int sum;
     4      int index;
     5      public Pair(int s, int i) {
     6          this.sum = s;
     7          this.index = i;
     8      }
     9  }
    10  
    11  public class Solution {
    12  
    13      public int[] subarraySumClosest(int[] nums) { 
    14         if(nums == null || nums.length == 0) return null;
    15         if(nums.length == 1) return new int[]{0, 0};
    16         //结果集数组
    17         int[] res = new int[2];
    18         
    19         int len = nums.length;
    20         //遍历一次nums,获得Pair数组,其中,前0个数的和是0
    21         Pair[] sums = new Pair[len + 1]; 
    22         sums[0] = new Pair(0,0);
    23         for(int i = 1; i <= len; i++) {
    24             sums[i] = new Pair(sums[i - 1].sum + nums[i - 1], i);
    25         }
    26         
    27         Arrays.sort(sums, new  Comparator<Pair>(){
    28             public int compare(Pair p1, Pair p2) {
    29                 return p1.sum - p2.sum;
    30             }
    31         });
    32         
    33         //排序完成后,遍历sums数组,找到离0最近的子数组,从角标1开始。
    34         int ans = Integer.MAX_VALUE; //answer
    35         for(int i = 1; i <= len; i++) {
    36             if(ans > sums[i].sum - sums[i - 1].sum) { 
    37                 ans = sums[i].sum - sums[i - 1].sum;
    38                 //Pair 记录的是前几个数的和,前0,1,2个等等,对应nums中的角标需要-1;
    39                 int[] temp = new int[]{sums[i].index - 1, sums[i - 1].index - 1};
    40                 Arrays.sort(temp);
    41                 //前5个数的和-前3个数的和离0最近,则需要返回的是第4,第5个的角标,所以temp[0]+1;
    42                 res[0] = temp[0] + 1; 
    43                 res[1] = temp[1];
    44             }
    45         }
    46         return res;
    47      }
    48  }
    View Code

     8 子数组之和(求子数组,先写出来前缀和,sum(i,j) = sum(j) - sum(i - 1),然后看它和所求的关系)

    http://www.lintcode.com/zh-cn/problem/subarray-sum/

    注意点:子数组和为0,代表存在位置,sum(j) 等于sum(i-1)。

           既然需要sum(i - 1),那为了求0位置的和同时能用到上面的递推关系,所以在-1位置放一个0;

          两sum相等,相当于去重,hash表天然就是实现是否存在,相等问题的,所以使用hashMap存放数据。

     1 public ArrayList<Integer> subarraySum(int[] nums) {
     2       if(nums == null || nums.length == 0) return null;
     3       ArrayList<Integer> res = new ArrayList<Integer>();
     4       Map<Integer, Integer> map = new HashMap();
     5       map.put(0, -1);
     6       int sum = 0;
     7       for(int i = 0; i < nums.length; i++) {
     8           sum += nums[i];
     9           if(map.get(sum) != null) {
    10               res.add(map.get(sum) + 1);
    11               res.add(i);
    12               return res;
    13           }
    14           map.put(sum, i);
    15       }
    16       return null;
    17   }
    View Code

    数据结构

    1 带最小值操作的栈

    http://www.lintcode.com/zh-cn/problem/min-stack/#

    注意点: 用另一个栈依次记录最小值。

     1 public class MinStack {
     2  
     3     //minStack的构造放到构造函数中比较好。
     4    Stack<Integer> minStack = new Stack<Integer>();
     5    Stack<Integer> s ;
     6     
     7     public MinStack() {
     8         // do initialize if necessary
     9        s = new Stack<Integer>();
    10     }
    11 
    12     public void push(int number) {
    13         // write your code here
    14         s.push(number);
    15         if(minStack.isEmpty() || minStack.peek() >= number) minStack.push(number);
    16     }
    17 
    18     public int pop() {
    19         // write your code here
    20         int number = s.pop();
    21         if(number == minStack.peek()) minStack.pop();
    22         return number;
    23     }
    24 
    25     public int min() {
    26         // write your code here
    27         
    28         return minStack.peek();
    29     }
    30 }
    View Code

    2 用栈实现队列 

    http://www.lintcode.com/zh-cn/problem/implement-queue-by-two-stacks/#

    3 直方图最大矩形覆盖(栈)

    http://www.lintcode.com/zh-cn/problem/largest-rectangle-in-histogram/#

    注意点: 递增栈,每次角标出栈时才计算对应角标高度的直方图面积。(while循环里,栈内弹出一个数需要O(1),弹出n个数需要O(n),所以while的平均时间为O(1),所以

        总体时间就只是for的时间,O(n))。

        高度中找左边和右边第一个比他小的位置,然后就是此高度对应的宽度。

     1  public int largestRectangleArea(int[] height) {
     2      if(height == null || height.length == 0) return 0;
     3      Stack<Integer> s = new Stack<Integer>();
     4      int max = 0;
     5      for(int i = 0; i <= height.length; i++) {
     6          int currHeight = (i == height.length)?-1:height[i];
     7          while(!s.isEmpty() && currHeight <= height[s.peek()]) {
     8              int h = height[s.pop()];
     9              int w = s.isEmpty()? i: i - s.peek() - 1;
    10              max = Math.max(max, h*w);
    11          }
    12          s.push(i);
    13      }
    14      return max;
    15  }
    View Code

     

    4 哈希表原理(增删查的复杂度O(1),二叉查找树logn)

    Cache (一个大的哈希表):memory级别的访问, ns级别,500M/b
    数据库:文件系统访问,硬盘,微秒级别,500k/b

     1 public void hashFunc(String key) {
     2       //hash本身就是杂乱无章的表示。所以不要去理解表达的含义,大概类似于把key按33进制表示出来,同时让他最后的值处于HASH_TABLE_SIZE的范围中。
     3       int sum = 0;
     4       for(int i = 0; i < key.length(); i++ ) {
     5           sum = sum * 33 + (int)key.charAt(i);
     6           sum = sum % HASH_TABLE_SIZE;  //如果不包含这一步,则相当于把key当成33进制数表示出来。   1234 按十进制表达: ((1*10 + 2)*10+3)*10 + 4;      
     7                                         //HASH_TABLE_SIZE 表示开辟的数组大小,实际存储的数据size/HASH_TABLE_SIZE = 1/10 最好,否则size再大,
     8                                         //产生冲突的概率会增大。每一次操作都保证sum在HASH_TABLE_SIZE的范围内。
     9     
    10       }
    11       return sum;
    12   }    
    View Code

    5 重哈希(需要把所有的数重新计算插入一遍,很麻烦,所以尽量避免重哈希的出现,开始定义hash大小时数组开的空间大点。)

    http://www.lintcode.com/zh-cn/problem/rehashing/

    注意点: 增加链表时,一定要new,而且是· .next = new ListNode,不然赋值不过来。不知道地址传递到底是怎么传的。

     1  public ListNode[] rehashing(ListNode[] hashTable) {
     2         if(hashTable == null || hashTable.length == 0) return hashTable;
     3         ListNode[] newHash = new ListNode[hashTable.length * 2];
     4         int len = newHash.length;
     5         for(int i = 0; i < hashTable.length; i++) {
     6             ListNode node = hashTable[i];
     7             int index = 0;
     8             while(node != null ) {
     9                  index = (node.val%len + len) % len;
    10                  if(newHash[index] == null) {
    11                      newHash[index] = new ListNode(node.val);
    12                      node = node.next;
    13                      continue;
    14                  } 
    15                  ListNode head = newHash[index];
    16                  while( head.next != null) {
    17                      head = head.next;
    18                  }
    19                 head = new ListNode(node.val);
    20           
    21                 node = node.next;
    22             }
    23         }
    24         return newHash;
    25     }
    View Code

     6 快乐数(hash)

    http://www.lintcode.com/zh-cn/problem/happy-number/

    注意点: 注意按位取元素的方法

     1 private int getNextHappy(int n) {
     2         int sum = 0;
     3         while (n != 0) {
     4             sum += (n % 10) * (n % 10);
     5             n /= 10;
     6         }
     7         return sum;
     8     }
     9     
    10     public boolean isHappy(int n) {
    11         HashSet<Integer> hash = new HashSet<Integer>();
    12         while (n != 1) {
    13             if (hash.contains(n)) {
    14                 return false;
    15             }
    16             hash.add(n);
    17             n = getNextHappy(n);
    18         }
    19         return true;
    20     }
    View Code

     7 LRU缓存策略

    http://www.lintcode.com/zh-cn/problem/lru-cache/

    注意点: node结点写在主类里面,因为它只需要在此类里暴露,不需要对外显示。

         一共有两种存储的数据结构,map存放指定容量的key,value数据,LinkedList存放各种数据的前后放入关系。所以操作数据时,要同时维护这两种数据结构,get方法只需要维护链表,set方法两个都需要维护。

    (堆相关)

     8 数据流中位数    优先队列/heap :O(log N) Add    O(log N) Remove   O(1) Min/Max    二叉树实现的,根节点是最值,每次移除根节点,都需要从剩下的结点中找到最值

              再移到根上,所以remove是O(logn)。堆排序只能保证根是最大(最小),不能保证整体是按照顺序来排序的。

    http://www.lintcode.com/zh-cn/problem/data-stream-median/ 

    注意点: offer  poll方法

        maxHeap里存放小于等于中位数的数字,minHeap里放大于中位数的数字。 中位数,则 maxHeap.size() == minHeap.size() 或者maxHeap.size() == minHeap.size()+1

     1  public int[] medianII(int[] nums) {
     2         // write your code here  
     3     if(nums == null || nums.length == 0) return null;
     4     PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
     5     PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(1, new Comparator<Integer>(){
     6         //@Override   可以不写,但是compare方法参数必须是Integer,不能是int
     7         public int compare(Integer x, Integer y) {
     8             return y - x;
     9         }
    10     });
    11     int[] res = new int[nums.length];
    12     res[0] = nums[0];
    13     maxHeap.offer(nums[0]);
    14     for(int i = 1; i < nums.length; i++) {
    15         if(nums[i] <= maxHeap.peek()) {
    16             maxHeap.offer(nums[i]);
    17         } else {
    18             minHeap.offer(nums[i]);
    19         }
    20         
    21         //开始进入两个元素时,size上,maxHeap = minHeap 或者 maxHeap = minHeap +2,经过下面的if语句,转变成maxHeap = minHeap 
    22         // 每一轮进来后,只会出现maxHeap = minHeap 或者maxHeap = minHeap +1两种情况。(类似一种递推的关系)
    23         if(maxHeap.size() > minHeap.size() + 1) {
    24             minHeap.offer(maxHeap.poll());
    25         } else if( maxHeap.size() < minHeap.size()) {
    26             maxHeap.offer(minHeap.poll());
    27         } 
    28         res[i] = maxHeap.peek();
    29     }
    30     return res;    
    31 }
    View Code

     9 堆化  (有点堆排序的意思)

    http://www.lintcode.com/zh-cn/problem/heapify/

    注意点:    0         1          2      3      4      5     6      原序列

        1   2      3       4       5      6            原序列元素对应的子树角标。

        A[0]肯定是最小值。

         siftdown的O(n)遍历方式很独特,从中间开始遍历。

     1 //   0 1 2 3 4 5 6 7  len = 8,   mid = 3     对于位置i,两个子树2i+1,2i+2;对于位置i-1,子树2(i-1) +1, 2(i-1) +2,即2i-1和2i。
     2                                              //也就是说 i-1,i-1恰好能连续覆盖掉2i-1,2i,2i+1,2i+2;
     3  //   0 1 2 3 4 5 6 7 8  len = 9, mid = 4
     4  
     5     public void heapify(int[] A) {
     6         // write your code here
     7         //O(n)完成,只遍历一次,但是遍历的方式不是简单的从头到尾,而是从中间往左。
     8         int mid = (A.length - 1)/2;
     9         for(int i = mid; i >=0; i--) {
    10             siftdown(A, i);
    11         }
    12         
    13     }
    14     
    15     private void siftdown(int[] A, int k) {
    16         int son = 0;
    17         while(2*k+1 < A.length) {   //从后往前保证 两个子树比根小,即有一定顺序。如果靠前的位置发生过swap,那也要保证swap之后,后面的位置还是有序
    18                                     //所以有k = son
    19             son = 2*k+1;
    20             if(2*k+2 < A.length && A[2*k+2] <= A[son] ) son = 2*k+2; //son是两个子树中的较小的一个
    21             
    22             if(A[son] < A[k]) {
    23                 swap(A, son, k);
    24                 k = son;
    25             } else {
    26                 break;
    27             }
    28         }
    29         
    30     }
    31     private void swap(int[] A, int x, int y) {
    32         int temp = A[x];
    33         A[x] = A[y];
    34         A[y] = temp;
    35     }
    View Code

     10 丑数

    http://www.lintcode.com/zh-cn/problem/ugly-number/

    http://www.lintcode.com/zh-cn/problem/ugly-number-ii/#

    注意点: 不理解丑数2的话看代码里的解释。

     1  public int nthUglyNumber(int n) {
     2      int[] uglyArr = new int[n];
     3      uglyArr[0] = 1;
     4      //p2,p3,p5代表三个指针,指向uglyArr数组的索引。
     5      int p2 = 0, p3=0, p5 = 0;
     6      for(int i= 1; i < n; i++) {
     7          //  <= 说明此索引位置的丑数已经乘以过2了,即已有的丑数数组中已经包含由此位置丑数*2所对应的丑数了,
     8          //  那么下一轮再乘的时候,就不能用此位置的丑数*2了,要用下一个丑数来乘。
     9          //  所以p2表示:当前待乘以2来候选作为下一个丑数的数的角标
    10          //为啥不是用uglyArr[i - 1]来乘2呢,比如1, 2,,3 用 3 *2 显然比 2* 2大,所以下一个丑数不是3*2。
    11          //所以应该记录的是之前的丑数,1,2,3是否乘过2,3,5,p2= 1,p3= 1, p5 = 0表示5还没有乘过角标0的数,2没有乘过角标1的数,3没有乘过角标1的数。
    12          if(uglyArr[p2] * 2 <= uglyArr[i - 1]) p2++;
    13          if(uglyArr[p3] * 3 <= uglyArr[i - 1]) p3++;
    14          if(uglyArr[p5] * 5 <= uglyArr[i - 1]) p5++;
    15          
    16          //这一轮最小值是乘的2,3还是5会在下一轮通过if判断出来,判断出来后,p2,p3,p5中有且只有一个指针会移动1个位置。
    17          uglyArr[i] = Math.min(uglyArr[p2] * 2, 
    18                         Math.min(uglyArr[p3] * 3, uglyArr[p5] * 5));
    19      }
    20      return uglyArr[n - 1];
    21  }
    View Code

     11.字符串查找

    http://www.lintcode.com/zh-cn/problem/strstr/

    注意点: O(n)实现 Rabin-Karp算法

      1234  : 234=10(123-100)+4 = 123*10+4-1000 此处用的是后面的计算方式

      (a+b)%b= (a%b+b%b)%b= a%b  这正是当hashcode<0时采取的做法,也就是对它取模,hashcode%HASH_SIZE=(hashcode+HASH_SIZE)%HASH_SIZE

     1 /** 验证下面的结论是否普遍成立:
     2      *     1%11*10%11*10%11=100%11=1  power
     3      *     5%11*10%11*10%11= 5    =1 * 5 
     4      *  结论是:成立
     5      */
     6     public static void main(String[] args) {
     7         int HASH_SIZE=1000000;
     8         for(int numberSize = 2; numberSize < 10; numberSize++) {
     9             int power = 1;
    10             for(int i = 0; i <4; i++) {
    11                 power = (power*31)%HASH_SIZE;
    12             }
    13             for(int i =1; i < 10; i++) {
    14                 int count = 0;
    15                 int num = i;
    16                 int count0 = (num* power)%HASH_SIZE;
    17                 for(int j = 0; j < 5; j++) {
    18                     if(j != 0) num = 0;
    19                     count = (count*31+num)%HASH_SIZE;
    20                 }
    21                 if(count != count0){
    22                     System.out.println(i);
    23                     break;
    24                 }
    25             }
    26             System.out.println(numberSize+"::finish");
    27         }
    28     }
    验证
     1 private int HASH_SIZE = 1000000;
     2 
     3     public int strStr(String source, String target) {
     4         // Write your code here
     5         if (source == null || target == null) {
     6             return -1;
     7         }
     8         int m = source.length();
     9         int n = target.length();
    10         if (n == 0) {
    11             return 0;
    12         }
    13         if (m == 0) {
    14             return -1;
    15         }
    16         int targetCode = 0;
    17         for (int i = 0; i < n; i++) {
    18             targetCode = (targetCode * 31 + target.charAt(i)) % HASH_SIZE;
    19         }
    20         int power = 1;
    21         for (int i = 0; i < n; i++) {
    22             power = (power * 31) % HASH_SIZE;
    23         }
    24         int hashCode = 0;
    25         for (int i = 0; i < m; i++) {
    26             //只有一开始i = n-1 时hashCode记录的是n个数的hash值,
    27             //之后一直记录的是n+1个数的值,所以power才要乘31^n 而不是31^(n-1)
    28             hashCode = (hashCode * 31 + source.charAt(i)) % HASH_SIZE;
    29             if (i < n - 1) {
    30                 continue;
    31             }
    32             if (i >= n) {
    33                 hashCode = hashCode - (source.charAt(i - n) * power)% HASH_SIZE ;
    34                 //为啥可能出现hashcode<0? 因为新添加的一位导致hashcode的值>HASH_SIZE,出现了取模的情况,
    35                 // 而 a%b = (a+b)%b,所以<0的情况,原本的hashcode计算方式应该是:
    36                 // hashcode = hashCode + HASH_SIZE - (source.charAt(i - n) * power)% HASH_SIZE ;
    37                 // 所以如果遇到<0的情况,加HASH_SIZE就好了。
    38                 if (hashCode < 0) {
    39                     hashCode += HASH_SIZE;
    40                 }
    41             }
    42             // 0~n-1  i=n-1, 0 = i - n+1
    43             // 1~n    i=n,   1 = i - n+1
    44             if (hashCode == targetCode) {
    45                 if (source.substring(i - n + 1, i + 1).equals(target)) {
    46                     return i - n + 1;
    47                 }
    48 
    49             }
    50         }
    51         return -1;
    52     }
    View Code

     

    graph and search

    1 克隆图

    http://www.lintcode.com/zh-cn/problem/clone-graph/#

    拓扑排序

    http://www.lintcode.com/zh-cn/problem/topological-sorting/#

    注意点:图肯定要用hashMap

        遍历完图的方式:while(start < res.size()) { start++}   res动态增长,size变化,所有结点都加入进去后,就不变了,而start也增长,实现遍历完全的目的。

     1 public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
     2         //图的BFS,类似二叉树的BFS,不过需要统计邻居关系,避免已经访问过的邻居重复访问,所以用Map+ Queue实现。
     3         //Queue可以用ArrayList + 头索引的位置来表示
     4         if(node == null) return node;
     5         ArrayList<UndirectedGraphNode> list = new ArrayList();  //放原先的结点
     6         Map<UndirectedGraphNode,UndirectedGraphNode> map = new HashMap();  //放复制节点和原先结点的映射关系
     7         int start = 0;
     8         
     9         list.add(node);
    10         map.put(node, new UndirectedGraphNode(node.label));
    11         while(start < list.size()) {
    12             UndirectedGraphNode curr = list.get(start++);
    13             for(int i = 0; i < curr.neighbors.size(); i++) {
    14                 if(!map.containsKey(curr.neighbors.get(i))) {
    15                     list.add(curr.neighbors.get(i));
    16                     map.put(curr.neighbors.get(i), new UndirectedGraphNode(curr.neighbors.get(i).label));
    17                 }
    18             }
    19         }
    20         
    21         // copy edge
    22         for(int i = 0; i < list.size(); i++) {
    23             UndirectedGraphNode curr = list.get(i);
    24             for(int j = 0; j < curr.neighbors.size(); j++) {
    25                 map.get(curr).neighbors.add(map.get(curr.neighbors.get(j)));
    26             }
    27         }
    28         return map.get(node);
    29     }
    View Code

     2 全排列(DFS)

    http://www.lintcode.com/zh-cn/problem/permutations/

    http://www.lintcode.com/zh-cn/problem/subsets/   子集

    http://www.lintcode.com/zh-cn/problem/subsets-ii/#

    http://www.lintcode.com/zh-cn/problem/permutations-ii/#

    http://www.lintcode.com/zh-cn/problem/combination-sum/#     list里add一个元素,再做dfs,然后再remove掉

    注意点: 写递归,想清楚两件事:

                1.递归是做了一件什么样的事情,和参数的关系是什么

                2.想清楚递归在什么时候return

                3.想清楚递归关系,把大问题化解成小问题解决。

    错误点:  返回  List<List<Integer>>,则声明为:List<List<Integer>> rst = new ArrayList<List<Integer>>();    List<Integer> list = new ArrayList<Integer>();

        返回ArrayList<ArrayList<Integer>>,  声明为:ArrayList<ArrayList<Integer>> rst = new ArrayList<ArrayList<Integer>>();

                             ArrayList<Integer> list = new ArrayList<Integer>();   按上面的声明无法通过编译

     1 public List<List<Integer>> permute(int[] nums) {
     2     // write your code here
     3     if(nums == null) return null;
     4     List<List<Integer>> rst = new ArrayList<List<Integer>>();
     5     ArrayList<Integer> list = new ArrayList<Integer>();
     6     if(nums.length == 0) {
     7         rst.add(list);
     8         return rst;
     9     }
    10     helper(rst, list, nums );
    11     return rst;
    12 }
    13 
    14 public void helper(List<List<Integer>> rst, ArrayList<Integer> list, int[] nums){
    15     if(list.size() == nums.length) {
    16         //不能rst.add(list) 地址传递,最后内容都没了
    17         rst.add(new ArrayList<Integer>(list));
    18         return;
    19     }
    20     for(int i = 0; i < nums.length; i++) {    //假设nums={1,2,3,4},最外的循环进来,for4次对应四种情况:     [ ]
    21                                               //                                                                |--[1]
    22                                               //                                                                |--[2]
    23                                               //                                                                |--[3]
    24                                               //                                                                |--[4]
    25                                               //对于每一种情况,比如[1],又分为了三种  [1]
    26                                               //                                         |--[2]
    27                                               //                                         |--[3]
    28                                               //                                         |--[4]
    29                                               //......最后直到list.size()==nums.length,所有元素都放进去了,才作为一次结果返回。
    30         
    31         if(list.contains(nums[i])) {
    32             continue;
    33         }
    34         list.add(nums[i]);
    35         helper(rst, list, nums);
    36         list.remove(list.size() - 1);
    37     }
    38 }
    View Code

    3 N皇后问题

    http://www.lintcode.com/zh-cn/problem/n-queens/#

    注意点:分成4块,每块函数各司其职

    错误点:     (cols.get(i) == j)?sb.append('Q'):sb.append('.'); (错)     sb.append(j == cols.get(i) ? 'Q' : '.');(对)  三目表达式,一个整体

     1  ArrayList<ArrayList<String>> solveNQueens(int n) {
     2     if(n <= 0) return null;
     3     ArrayList<ArrayList<String>> rst = new ArrayList<ArrayList<String>>();
     4     search(rst, new ArrayList<Integer>(), n);
     5     return rst;
     6         
     7  }
     8 
     9  private void search(ArrayList<ArrayList<String>> rst, ArrayList<Integer> cols, int n) {
    10      if(cols.size() == n) {
    11          rst.add(drawChess(cols));
    12          return;
    13      }
    14      for(int i = 0; i < n; i++) {
    15          if(!isValid(cols, i)) {
    16             continue; 
    17          }
    18          cols.add(i);
    19          search(rst, cols, n);
    20          cols.remove(cols.size() - 1);
    21      }
    22  }
    23  //查看第cols.size()行的第colIndex 列是否合法
    24  //根据cols元素的放法的定义,不可能出现同一行,只可能有同一列或者同一斜行的情况。
    25  private boolean isValid(ArrayList<Integer> cols, int colIndex) {
    26      int rowIndex = cols.size();
    27      for(int i = 0; i < rowIndex; i++) {
    28          if(cols.get(i) == colIndex) return false;
    29          // right-top  to left-down
    30         // 。Q 。 。
    31         // 。。 Q  。   左上到右下情况下的相同斜线:  (0, 1)  (1,2)  行序号-列序号的值相等。
    32         
    33         // 。。 。 Q
    34         // 。。 Q  。   右上到左下情况下的相同斜线:  (0, 3)  (1,2)  行序号+列序号的值相等。
    35          if(cols.get(i) + i == rowIndex + colIndex) return false;
    36          if(cols.get(i) - i == colIndex - rowIndex ) return false;
    37      }
    38      return true;
    39  }
    40  private ArrayList<String> drawChess(ArrayList<Integer> cols) {
    41      ArrayList<String> list = new ArrayList<String>();
    42      for(int i = 0; i < cols.size(); i++) {
    43          StringBuilder sb = new StringBuilder();
    44         for(int j = 0; j < cols.size(); j++) {
    45             //(cols.get(i) == j)?sb.append('Q'):sb.append('.');
    46             sb.append(j == cols.get(i) ? 'Q' : '.');
    47         }
    48         list.add(sb.toString());
    49      }
    50      return list;
    51  }
    View Code

    4 单词接龙

    http://www.lintcode.com/zh-cn/problem/word-ladder/      BFS   找最短路

    http://www.lintcode.com/zh-cn/problem/word-ladder-ii/#    找所有方案,需要DFS,同时也要找最短路对应的所有方案,所以是DFS+BFS

    注意点: BFS,因为每次只变一步,可以画出一张单词变化图出来, lot-log-pog  

        第一种方法超时了,差别主要在找下一个合法单词的方式上,一种是遍历dict,依次判断每个单词是否是合法的单词,另一种是先写出当前单词的所有的合法

        改变单词来,然后判断它是否在dict中。结果是第二种方式更优,为啥??

      1  public int ladderLength(String start, String end, Set<String> dict) {
      2     // 超时了,dict很大的时候,isValidChange 用时过长。
      3     if(start == null || end == null || dict == null) return 0;
      4     if(isValidChange(start,end)) return 2;
      5     List<String> list = new ArrayList<String>();
      6     list.add(start);
      7     return searchValidChange(list, dict, end);
      8 }
      9 private int searchValidChange(List<String> list, Set<String> dict,String end) {
     10     int level = 1;
     11     int pos = 0;
     12     while(list.size() < dict.size() + 1) {
     13         int len = list.size();
     14         while(pos < len) {
     15             for(String s1 : dict) {
     16                 if(list.contains(s1)) continue;
     17                 if(isValidChange(list.get(pos), s1)) {
     18                     if(isValidChange(s1, end)) return level+2;
     19                     list.add(s1);
     20                 }
     21             }
     22             pos++;
     23         }
     24         level++;
     25     }
     26     return 0;
     27 }
     28 private boolean isValidChange(String s1, String s2) {
     29     if(s1.length() != s2.length()) return false;
     30     int count = 0;
     31     for(int i = 0; i < s1.length(); i++) {
     32     if(s1.charAt(i) == s2.charAt(i)) continue;
     33         count++;    
     34         //if(count > 1) return false;
     35     }
     36     return count == 1;
     37 }
     38 //----------------------------------------------------
     39  public int ladderLength(String start, String end, Set<String> dict) {
     40         if (dict == null) {
     41             return 0;
     42         }
     43 
     44         if (start.equals(end)) {
     45             return 1;
     46         }
     47         
     48         dict.add(start);
     49         dict.add(end);
     50 
     51         HashSet<String> hash = new HashSet<String>();
     52         Queue<String> queue = new LinkedList<String>();
     53         queue.offer(start);
     54         hash.add(start);
     55         
     56         int length = 1;
     57         while(!queue.isEmpty()) {
     58             length++;
     59             int size = queue.size();
     60             for (int i = 0; i < size; i++) {
     61                 String word = queue.poll();
     62                 for (String nextWord: getNextWords(word, dict)) {
     63                     if (hash.contains(nextWord)) {
     64                         continue;
     65                     }
     66                     if (nextWord.equals(end)) {
     67                         return length;
     68                     }
     69                     
     70                     hash.add(nextWord);
     71                     queue.offer(nextWord);
     72                 }
     73             }
     74         }
     75         return 0;
     76     }
     77 
     78     // replace character of a string at given index to a given character
     79     // return a new string
     80     private String replace(String s, int index, char c) {
     81         char[] chars = s.toCharArray();
     82         chars[index] = c;
     83         return new String(chars);
     84     }
     85     
     86     // get connections with given word.
     87     // for example, given word = 'hot', dict = {'hot', 'hit', 'hog'}
     88     // it will return ['hit', 'hog']
     89     private ArrayList<String> getNextWords(String word, Set<String> dict) {
     90         ArrayList<String> nextWords = new ArrayList<String>();
     91         for (char c = 'a'; c <= 'z'; c++) {
     92             for (int i = 0; i < word.length(); i++) {
     93                 if (c == word.charAt(i)) {
     94                     continue;
     95                 }
     96                 String nextWord = replace(word, i, c);
     97                 if (dict.contains(nextWord)) {
     98                     nextWords.add(nextWord);
     99                 }
    100             }
    101         }
    102         return nextWords;
    103     }
    View Code
     1 //懒得看了,bfs写的就问题很大。用一个队列就能解决的问题,套了半天map,死循环,还绕。
     2 private Map<String, Integer> map;
     3 private int minLen = Integer.MAX_VALUE;
     4 private List<List<String>> rsts;
     5 private Set<String> dict;
     6 public List<List<String>> findLadders(String start, String end, Set<String> dict) {
     7     // write your code here  
     8     if(start == null || end == null) return null;
     9     rsts = new ArrayList<>();
    10     List<String> rst = new ArrayList<String>();
    11     rst.add(start);
    12     if(start.equals(end)) {
    13         rsts.add(new ArrayList<String>(rst));
    14         return rsts;
    15     }
    16     if(dict == null) return null;
    17     map = findShortestLen(dict, end);
    18     this.dict = dict;
    19     dict.add(end);
    20     //dict.add(start);
    21     dfs(rst, start, end);
    22     return rsts;
    23 }
    24 //dfs
    25 private void dfs(List<String> rst,String start, String end) {
    26     if(map.get(start) != null && map.get(start) == 2 && rst.size() + 1 == minLen) {
    27         List<String> addRst = new ArrayList<String>(rst);
    28         addRst.add(end);
    29         rsts.add(addRst);
    30     }
    31     List<String> list = findNextWords(dict, start);
    32     for(String s : list) {
    33         //List<String> addList = new ArrayList<String>();
    34         if(!map.containsKey(s)) continue;
    35         if(minLen < rst.size() + map.get(s)) continue;
    36         else {
    37             minLen = rst.size() + map.get(s);    
    38             rst.add(s);
    39             dfs(rst, s, end );
    40             rst.remove(rst.size() - 1);    
    41         }
    42         
    43     }
    44     return;
    45 }
    46 //bfs    
    47 private Map<String, Integer> findShortestLen(Set<String> dict, String end) {
    48     Map<String, Integer> map = new HashMap<>();
    49     map.put(end, 1);
    50     int len = 1;
    51     while(map.size() < dict.size()) {  ///zzz, abc, abd,   zzz永远也放不进map,死循环,先不管。    
    52         Map<String, Integer> temp = new HashMap<>();
    53         for(String s1 : map.keySet()) {
    54             if(map.get(s1) != len) continue;
    55             List<String> list = findNextWords(dict, s1);
    56             if(list == null) continue;
    57             for(String s2 : list) {
    58                 if(map.containsKey(s2) || temp.containsKey(s2)) continue;
    59                 temp.put(s2, len + 1);
    60             }
    61         }
    62         len++;
    63         map.putAll(temp);
    64     }
    65     return map;
    66 }
    67 private List<String> findNextWords(Set<String> dict, String end) {
    68     List<String> list = new ArrayList<String>();
    69     for(int i = 'a'; i <= 'z'; i++) {
    70         for(int j = 0; j < end.length(); j++) {
    71             if(i == end.charAt(j)) continue;
    72             String s = replaceOneChar(end, j, (char)i);
    73             if(dict.contains(s)) list.add(s);
    74         }
    75     }
    76     return list;
    77 }
    78 private String replaceOneChar(String end, int pos, char c) {
    79     char[] chars = end.toCharArray();
    80     chars[pos] = c;
    81     return Arrays.toString(chars);
    82 }
    接龙2_Me_wrong
     1 public List<List<String>> findLadders(String start, String end, Set<String> dict) {
     2     List<List<String>> rsts = new ArrayList<>();
     3     List<String> rst = new ArrayList<String>();
     4     Map<String,List<String>> map = new HashMap(); 
     5     Map<String, Integer> distance = new HashMap();
     6     dict.add(start);
     7     dict.add(end); //避免dict中有无start和end造成的分类讨论
     8     bfs(map, distance, start , end, dict);
     9     dfs(rsts,map, distance,rst, end, start);
    10     return rsts;
    11 }
    12 //从end开始添加
    13 private void dfs(List<List<String>> rsts, Map<String,List<String>> map, Map<String, Integer> distance, List<String> rst, String curr,
    14                  String start) {
    15     rst.add(curr);
    16     if(curr.equals(start)) {
    17         Collections.reverse(rst);
    18         rsts.add(new ArrayList(rst));
    19         Collections.reverse(rst);
    20         return;
    21     }
    22 /*    不要这样取元素
    23     List<String> nexts = findNexts(dict, curr);
    24     for(String next : nexts) {
    25         if(distance.get(next) +1 == distance.get(curr)) {
    26             dfs(rsts,map, distance, rst, next, start, dict);
    27         }
    28     }*/
    29        /* 这样只能取出一种结果来
    30         List<String> list = map.get(curr);
    31         dfs(rsts,map, distance, rst, list.get(list.size() - 1) , start, dict);*/
    32         List<String> list = map.get(curr);
    33         for(String s : list) {
    34             if(distance.get(s) +1 == distance.get(curr)) {
    35                 dfs(rsts,map, distance, rst, s , start);
    36             }
    37         }
    38     rst.remove(rst.size() - 1);
    39     
    40 }
    41 //计算每一个字符串到start的路径距离 
    42 private void bfs(Map<String,List<String>> map, Map<String, Integer> distance, String start, String end, Set<String> dict) {
    43     Queue<String> q = new LinkedList();
    44     q.offer(start);
    45     distance.put(start, 0);
    46     for(String s : dict) {
    47         map.put(s, new ArrayList());
    48     }
    49     while(!q.isEmpty()) {
    50         String curr = q.poll();
    51         List<String> nexts = findNexts(dict, curr);
    52         for(String next : nexts) {
    53         /*    这样只能取出一种接过来
    54             if(distance.containsKey(next)) continue;
    55             distance.put(next, distance.get(curr) + 1);
    56             map.get(next).add(curr);
    57             q.offer(next);*/
    58             map.get(next).add(curr);
    59             if(!distance.containsKey(next)) {
    60                 distance.put(next, distance.get(curr) + 1);
    61                 q.offer(next);
    62             }
    63         }
    64     }
    65 }
    66 private List<String> findNexts(Set<String> dict, String curr) {
    67     List<String> nexts = new ArrayList();
    68     for(char ch = 'a'; ch <='z'; ch++) {
    69         for(int i = 0; i < curr.length(); i++) {
    70             if (ch == curr.charAt(i)) continue;
    71             String s = curr.substring(0, i) + ch + curr.substring(i+1);
    72             if(dict.contains(s)) {
    73                 nexts.add(s);
    74             }
    75         }    
    76     }
    77     return nexts;
    78 }
    还是wrong,不知道哪里有错
  • 相关阅读:
    linux试题
    linux常用脚本
    nagios
    lvs/nginx/haproxy 负载均衡优缺点分析讲解
    一次SSLPeerUnverifiedException,SSLHandshakeException问题的分析
    [转]【安卓笔记】AsyncTask源码剖析
    linux下查看进程占用端口和端口占用进程命令
    which framework or library is best to use WebRTC
    [转]svn diff 替代工具
    [转]使用Subversion进行版本控制
  • 原文地址:https://www.cnblogs.com/ddcckkk/p/6844998.html
Copyright © 2020-2023  润新知