├── README.md └── src ├── ADT └── TreeNode.java ├── BFS └── 原点到特定点的最短路径.java ├── BackTracking ├── IP地址划分.java ├── N皇后.java ├── 和为某数的所有组合.java ├── 和为某数的所有组合2.java ├── 字符串划分成回文子串.java ├── 找出所有数字组合.java ├── 找出有重复数字的组合.java ├── 数字的所有不同组合.java ├── 数字键打出字母组合.java ├── 数独.java ├── 数组的所有子集.java ├── 数组的所有子集2.java ├── 矩阵查找单词.java └── 脑洞大开的矩阵查找单词.java ├── BinSearch ├── Sqrt.java ├── arrangeCoins.java └── singleNonDuplicate.java ├── DFS ├── 二叉树所有路径.java ├── 图的连通分量个数.java ├── 填充封闭区域.java ├── 太平洋和大西洋灌水.java ├── 岛屿的最大面积.java ├── 改变一组数的正负号使得它们的和为一给定数.java ├── 朋友圈.java ├── 查找最大的连通面积.java ├── 矩阵中的连通区域数量.java └── 被围绕的区域.java ├── DP ├── 信件排错.java ├── 分割整数 │ ├── 分割整数的最大乘积自写.java │ ├── 按平方数来分割整数.java │ └── 按平方数来分割整数自写.java ├── 字符串编辑 │ ├── 修改一个字符串为另一个字符串.java │ ├── 删除两个字符串的字符使它们相等.java │ ├── 复制粘贴字符.java │ └── 字符串复制粘贴.java ├── 强盗在环形街区抢劫.java ├── 强盗抢劫.java ├── 数组区间 │ ├── 子数组最大的和.java │ ├── 数组中等差递增子区间的个数.java │ └── 数组区间和.java ├── 最长摆动子序列_双数组.java ├── 母牛生产.java ├── 矩阵路径 │ ├── 爬楼梯方法总数.java │ └── 矩阵的总路径数.java ├── 经典 │ ├── 分割整数的最大乘积.java │ ├── 最长公共子序列.java │ ├── 最长递增子序列.java │ └── 矩阵的最小路径和.java ├── 股票买卖 │ ├── 买入和售出股票最大的收益.java │ ├── 只能进行k次的股票交易.java │ ├── 只能进行两次的股票交易.java │ ├── 股票问题通解.java │ ├── 需要交易费用的股票交易_多数组.java │ └── 需要冷却期的股票交易_双数组.java └── 背包 │ ├── 多维费用的背包.java │ ├── 多重背包.java │ ├── 字符串 │ ├── 分割整数构成字母字符串.java │ ├── 字符01构成最多的字符串.java │ └── 字符串按单词列表分割.java │ ├── 完全背包.java │ ├── 背包01不用装满.java │ ├── 背包01需要装满.java │ ├── 背包扩展 │ ├── 划分数组为和相等的两部分.java │ ├── 找零钱.java │ └── 组合总和.java │ └── 难啊 │ ├── 只能进行k次的股票交易.java │ └── 只能进行两次的股票交易.java ├── KeysKeyboard.java ├── 双指针 ├── 两数平方和.java ├── 单链表判环.java ├── 反转字符串中的元音字符.java ├── 回文字符串.java ├── 归并两个有序数组.java ├── 最长子序列加强版.java └── 查找和为9的数对.java ├── 排序 ├── 出现频率最高的k个数.java ├── 根据字符出现频率排序.java └── 荷兰国旗.java ├── 数学 ├── 公约公倍 │ └── 最大公约数和最小公倍数.java ├── 其他 │ ├── 乘积数组.java │ ├── 判断一个数是否是3的n次方.java │ ├── 平方数.java │ └── 找出数组中的乘积最大的三个数.java ├── 多数投票问题 │ └── 数组中出现次数多于二分之一n的的元素.java ├── 字符串加法减法 │ ├── 二进制加法.java │ └── 字符串加法.java ├── 相遇问题 │ └── 改变数组元素使所有的数组元素都相等.java ├── 素数 │ └── 生成素数序列.java ├── 进制转换 │ ├── 七进制.java │ └── 十转十六进制.java └── 阶乘 │ ├── 统计阶乘尾部有多少个0.java │ └── 统计阶乘的二进制尾部有多少个0.java ├── 数据结构 ├── 位运算 │ ├── 一个数是否为4的n次方.java │ ├── 一个数是否是2的n次方.java │ ├── 不用额外变量交换两个整数.java │ ├── 位运算基础.java │ ├── 判断一个数的位级表示是否不会出现连续的0和1.java │ ├── 字符串数组最大乘积.java │ ├── 找出数组中缺失的那个数.java │ ├── 找到仅有的两个不重复的数.java │ ├── 数组中唯一一个不重复的元素.java │ ├── 整数加法.java │ ├── 求一个数的补码.java │ ├── 统计1到n二进制1的个数.java │ ├── 统计两个数的二进制表示有多少位不同.java │ └── 翻转一个数的比特位.java ├── 哈希表 │ ├── 判断数组是否含有相同元素.java │ ├── 数组中的两个数和为给定值.java │ └── 最长和谐序列.java ├── 图 │ ├── 冗余连接.java │ └── 并查集.java ├── 字符串 │ └── 两个字符串包含的字符是否完全相同.java ├── 数组与矩阵 │ ├── 分隔数组.java │ ├── 寻找所有丢失的元素.java │ ├── 寻找所有重复的元素.java │ ├── 嵌套数组.java │ ├── 找出丢失的数和重复的数.java │ ├── 找出数组中最长的连续1.java │ ├── 找出数组中重复的数有条件限制.java │ ├── 把数组中的0移到末尾.java │ ├── 数组的度.java │ ├── 数组相邻差值的个数.java │ └── 矩阵 │ │ ├── 对角元素相等的矩阵.java │ │ ├── 有序矩阵查找.java │ │ ├── 有序矩阵查找第n小的数可重复.java │ │ └── 调整矩阵.java ├── 栈和队列 │ ├── 在另一个数组中比当前元素大的下一个元素.java │ ├── 循环数组中比当前元素大的下一个元素.java │ ├── 括号匹配.java │ ├── 数组中元素与下一个比它大的元素之间的距离.java │ ├── 最小值栈.java │ ├── 用栈实现队列.java │ └── 用队列实现栈.java ├── 树 │ ├── BST │ │ ├── BST中和为给定值的两个节点.java │ │ ├── 从有序数组中构造二叉查找树.java │ │ ├── 修剪二叉查找树.java │ │ ├── 在BST中查找两个节点之差的最小绝对值.java │ │ ├── 寻找BST中出现次数最多的节点.java │ │ ├── 寻找BST的第k个元素.java │ │ └── 把BST每个节点的值都加上比它大的节点的值.java │ ├── TreeNode.java │ ├── Trie │ │ ├── Trie求前缀和.java │ │ └── 实现一个Trie树.java │ ├── 层次遍历 │ │ ├── 一棵树每层节点的平均数.java │ │ ├── 得到左下角的节点.java │ │ └── 间隔遍历.java │ ├── 递归 │ │ ├── 平衡树.java │ │ ├── 树的操作 │ │ │ ├── 子树.java │ │ │ ├── 归并两棵树.java │ │ │ ├── 树的对称.java │ │ │ └── 翻转树.java │ │ ├── 树的高度.java │ │ ├── 节点 │ │ │ ├── 二叉查找树的最近公共祖先.java │ │ │ ├── 二叉树的最近公共祖先.java │ │ │ ├── 找出二叉树中第二小的节点.java │ │ │ └── 统计左叶子节点的和.java │ │ └── 路径 │ │ │ ├── 两节点的最长路径.java │ │ │ ├── 判断路径和是否等于一个数.java │ │ │ ├── 最小路径.java │ │ │ ├── 相同节点值的最大路径长度.java │ │ │ └── 统计路径和等于一个数的路径数量.java │ └── 遍历 │ │ ├── 中序非递归.java │ │ ├── 先序非递归.java │ │ └── 后序非递归.java └── 链表 │ ├── ListNode.java │ ├── 交换链表中的相邻结点.java │ ├── 从有序链表中删除重复节点.java │ ├── 分隔链表.java │ ├── 删除链表的倒数第n个节点.java │ ├── 回文链表.java │ ├── 归并两个有序的链表.java │ ├── 找出两个链表的交点.java │ ├── 根据有序链表构造平衡的BST.java │ ├── 链表元素按奇偶聚集.java │ ├── 链表十进制求和.java │ └── 链表反转.java └── 贪心 ├── 买卖股票.java ├── 修改一个数成为非递减数组.java ├── 分配饼干.java ├── 分隔字符串使同种字符出现在一起.java ├── 判断是否为子串.java ├── 投飞镖刺破气球.java ├── 根据身高和序号重组队列.java └── 种植花朵.java /src/ADT/TreeNode.java: -------------------------------------------------------------------------------- 1 | package ADT; 2 | 3 | /** 4 | Created by 周杰伦 on 2018/3/31. 5 | */ 6 | public class TreeNode { 7 | public int val; 8 | public TreeNode left; 9 | public TreeNode right; 10 | public TreeNode(int x) { val = x; } 11 | } 12 | -------------------------------------------------------------------------------- /src/BFS/原点到特定点的最短路径.java: -------------------------------------------------------------------------------- 1 | package BFS; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/3/31. 8 | */ 9 | public class 原点到特定点的最短路径 { 10 | //查询最短路径时,节点需要保存此时的长度信息,否则没办法得知长度。 11 | public static void main(String[] args) { 12 | int [][]a = {{1,1,0,1}, 13 | {1,0,1,0}, 14 | {1,1,1,1}, 15 | {1,0,1,1}}; 16 | System.out.println(minPathLength(a,3,3)); 17 | } 18 | // public static int minPathLength(int[][] grids, int tr, int tc) { 19 | // if (grids == null)return 0; 20 | // int m = grids.length; 21 | // int n = grids[0].length; 22 | // if (tr > m || tr < 0 || tc > n || tc < 0)return 0; 23 | // int [][]go = {{0,1},{0,-1},{1,0},{-1,0}}; 24 | // Queue queue = new LinkedList<>(); 25 | // int []start = {0,0}; 26 | // queue.offer(start); 27 | // int len = 0; 28 | // while (!queue.isEmpty()) { 29 | // int []a = queue.poll(); 30 | // int r = a[0]; 31 | // int c = a[1]; 32 | // 33 | // for (int i = 0;i < go.length;i ++) { 34 | // int []pos = new int[2]; 35 | // pos[0] = r + go[i][0]; 36 | // pos[1] = c + go[i][1]; 37 | // if (pos[0] >= 0 && pos[0] < m && pos[1] >= 0 && pos[1] < n) { 38 | // if (grids[pos[0]][pos[1]] == 1) { 39 | // grids[pos[0]][pos[1]] = 0; 40 | // if (pos[0] == tr && pos[1] == tc)return len; 41 | // queue.offer(pos); 42 | // } 43 | // 44 | // } 45 | // } 46 | // } 47 | // return len; 48 | // } 49 | 50 | 51 | 52 | 53 | public static int minPathLength(int[][] grids, int tr, int tc) { 54 | int[][] next = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; 55 | int m = grids.length, n = grids[0].length; 56 | Queue queue = new LinkedList<>(); 57 | queue.add(new Position(0, 0, 1)); 58 | while (!queue.isEmpty()) { 59 | Position pos = queue.poll(); 60 | for (int i = 0; i < 4; i++) { 61 | Position nextPos = new Position(pos.r + next[i][0], pos.c + next[i][1], pos.length + 1); 62 | if (nextPos.r < 0 || nextPos.r >= m || nextPos.c < 0 || nextPos.c >= n) continue; 63 | if (grids[nextPos.r][nextPos.c] != 1) continue; 64 | grids[nextPos.r][nextPos.c] = 0; 65 | if (nextPos.r == tr && nextPos.c == tc) return nextPos.length; 66 | queue.add(nextPos); 67 | } 68 | } 69 | return -1; 70 | } 71 | 72 | private static class Position { 73 | int r, c, length; 74 | public Position(int r, int c, int length) { 75 | this.r = r; 76 | this.c = c; 77 | this.length = length; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/BackTracking/IP地址划分.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/1. 8 | * 1 file committed: 回溯法 9 | * 5大题型 10 | * 1排列 全排列 有重复数字的排列 11 | * 2组合 重复元素组合 12 | * 3求和 重复元素求和 13 | * 4子集 重复元素子集 14 | * 5扩展题型 如ip划分 回文数划分 数字打出字母等。 15 | * 重点在于:递归前标记元素,每次完整递归结束需要清除标记元素。 16 | * 判断递归结束条件。 17 | * 细节问题如list的添加,contains使用等 18 | */ 19 | //1111 20 | //222 222 222 222 21 | // 55 55 55 55 22 | public class IP地址划分 { 23 | public static void main(String[] args) { 24 | 25 | } 26 | public List restoreIpAddresses(String s) { 27 | int i,j,k,m; 28 | ArrayList list = new ArrayList<>(); 29 | int len = s.length(); 30 | for (i = 1;i< 4 && i < len - 2;i ++) { 31 | for (j = i + 1;j < i + 4 && j < len - 1;j ++) { 32 | for (m = j + 1;m < j + 4 && m < len;m ++) { 33 | //substring后面的下标是不算在内的。 34 | String s1 = s.substring(0,i); 35 | String s2 = s.substring(i,j); 36 | String s3 = s.substring(j,m); 37 | String s4 = s.substring(m,len); 38 | if(isValid(s1) && isValid(s2) && isValid(s3) && isValid(s4)) 39 | { 40 | list.add(s1 + '.' + s2 + '.' + s3 + '.' + s4); 41 | } 42 | } 43 | } 44 | } 45 | return list; 46 | } 47 | 48 | public boolean isValid(String s) { 49 | if (s.length() == 0 || s.length() > 3 || s.charAt(0) == '0' && s.length() > 1 50 | || Integer.parseInt(s) > 255) { 51 | return false; 52 | }else return true; 53 | } 54 | 55 | // public List restoreIpAddresses(String s) { 56 | // List result = new ArrayList<>(); 57 | // doRestore(result, "", s, 0); 58 | // return result; 59 | // } 60 | 61 | // private void doRestore(List result, String path, String s, int k) { 62 | // if (s.isEmpty() || k == 4) { 63 | // if (s.isEmpty() && k == 4) 64 | // result.add(path.substring(1)); 65 | // return; 66 | // } 67 | // for (int i = 1; i <= (s.charAt(0) == '0' ? 1 : 3) && i <= s.length(); i++) { // Avoid leading 0 68 | // String part = s.substring(0, i); 69 | // if (Integer.valueOf(part) <= 255) 70 | // doRestore(result, path + "." + part, s.substring(i), k + 1); 71 | // } 72 | // } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/BackTracking/N皇后.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/2. 5 | */ 6 | public class N皇后 { 7 | public static void main(String[] args) { 8 | StringBuilder sb = new StringBuilder(); 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/BackTracking/和为某数的所有组合.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by 周杰伦 on 2018/4/2. 10 | */ 11 | public class 和为某数的所有组合 { 12 | public static void main(String[] args) { 13 | int []a = {2,3,6,7}; 14 | System.out.println(Arrays.toString((combinationSum(a,7).toArray()))); 15 | 16 | } 17 | 18 | public static List> combinationSum(int[] candidates, int target) { 19 | List arr = new ArrayList<>(); 20 | List> list = new ArrayList<>(); 21 | backTracking(arr, 0, 0, candidates, target, list); 22 | return list; 23 | } 24 | 25 | public static void backTracking(List arr,int cur,int sum,int[]nums, int target, List> list) { 26 | if (sum == target) { 27 | list.add(new ArrayList(arr)); 28 | return; 29 | } 30 | for (int i = cur;i < nums.length;i ++) { 31 | //终止条件很重要,否则会死循环 32 | if (sum + nums[i] <= target) { 33 | arr.add(nums[i]); 34 | sum += nums[i]; 35 | backTracking(arr, i, sum, nums, target, list); 36 | sum -= nums[i]; 37 | arr.remove(arr.size() - 1); 38 | } 39 | } 40 | return; 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/BackTracking/和为某数的所有组合2.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/2. 7 | */ 8 | public class 和为某数的所有组合2 { 9 | public static void main(String[] args) { 10 | int []a = {10, 1, 2, 7, 6, 1, 5}; 11 | System.out.println(Arrays.toString((combinationSum2(a,8).toArray()))); 12 | 13 | } 14 | 15 | public static List> combinationSum2(int[] candidates, int target) { 16 | List arr = new ArrayList<>(); 17 | List> list = new ArrayList<>(); 18 | Arrays.sort(candidates); 19 | backTracking(arr, 0, 0, candidates, target, list); 20 | return list; 21 | } 22 | 23 | public static void backTracking(List arr,int cur,int sum,int[]nums, int target, List> list) { 24 | if (sum == target) { 25 | if (!list.contains(arr)) 26 | list.add(new ArrayList(arr)); 27 | return; 28 | } 29 | for (int i = cur;i < nums.length;i ++) { 30 | //终止条件很重要,否则会死循环 31 | if (sum + nums[i] <= target) { 32 | arr.add(nums[i]); 33 | sum += nums[i]; 34 | backTracking(arr, i + 1, sum, nums, target, list); 35 | sum -= nums[i]; 36 | arr.remove(arr.size() - 1); 37 | } 38 | } 39 | return; 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/BackTracking/字符串划分成回文子串.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by 周杰伦 on 2018/4/2. 9 | */ 10 | public class 字符串划分成回文子串 { 11 | public static void main(String[] args) { 12 | System.out.println(Arrays.toString(partition("aab").toArray())); 13 | } 14 | public static List> partition(String s) { 15 | List arr = new ArrayList<>(); 16 | List> list = new ArrayList<>(); 17 | backTracking(s, 0, arr, list); 18 | return list; 19 | } 20 | public static void backTracking(String s,int left,List arr, List> list) { 21 | if (left == s.length()) { 22 | list.add(new ArrayList<>(arr)); 23 | return; 24 | } 25 | for (int i = left;i < s.length();i ++) { 26 | String substr = s.substring(left,i + 1); 27 | if (isHuiWen(substr)) { 28 | arr.add(substr); 29 | backTracking(s,i + 1,arr,list); 30 | arr.remove(arr.size() - 1); 31 | } 32 | } 33 | } 34 | public static boolean isHuiWen(String s) { 35 | if (s == null || s.equals(""))return false; 36 | if (s.length() == 1)return true; 37 | int l = 0,r = s.length() - 1; 38 | while (l < r) { 39 | if (s.charAt(l) != s.charAt(r))return false; 40 | l ++; 41 | r --; 42 | } 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/BackTracking/找出所有数字组合.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by 周杰伦 on 2018/4/1. 10 | */ 11 | public class 找出所有数字组合 { 12 | public static void main(String[] args) { 13 | int []a = {1,2,3}; 14 | System.out.println(Arrays.toString(permute(a).toArray())); 15 | } 16 | public static List> permute(int[] nums) { 17 | int m = nums.length; 18 | int []visit = new int[m]; 19 | List> list = new ArrayList<>(); 20 | ArrayList arr = new ArrayList<>(); 21 | dfs(arr, nums, visit, list); 22 | return list; 23 | } 24 | public static void dfs(ArrayList arr, int []nums, int[]visit, List> list) { 25 | if (arr.size() == nums.length) { 26 | list.add(new ArrayList<>(arr)); 27 | return; 28 | } 29 | for (int i = 0;i < nums.length;i ++) { 30 | if (visit[i] == 1) continue; 31 | visit[i] = 1; 32 | arr.add(nums[i]); 33 | dfs(arr, nums, visit,list); 34 | arr.remove(arr.size()-1); 35 | visit[i] = 0; 36 | } 37 | 38 | return; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/BackTracking/找出有重复数字的组合.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by 周杰伦 on 2018/4/1. 9 | */ 10 | public class 找出有重复数字的组合 { 11 | public List> permuteUnique(int[] nums) { 12 | List> ret = new ArrayList<>(); 13 | List permuteList = new ArrayList<>(); 14 | Arrays.sort(nums); 15 | boolean[] visited = new boolean[nums.length]; 16 | backtracking(permuteList, visited, nums, ret); 17 | return ret; 18 | } 19 | 20 | private void backtracking(List permuteList, boolean[] visited, int[] nums, List> ret) { 21 | if (permuteList.size() == nums.length) { 22 | ret.add(new ArrayList(permuteList)); 23 | return; 24 | } 25 | 26 | for (int i = 0; i < visited.length; i++) { 27 | if (i != 0 && nums[i] == nums[i - 1] && !visited[i - 1]) continue; 28 | if (visited[i]) continue; 29 | visited[i] = true; 30 | permuteList.add(nums[i]); 31 | backtracking(permuteList, visited, nums, ret); 32 | permuteList.remove(permuteList.size() - 1); 33 | visited[i] = false; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/BackTracking/数字的所有不同组合.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by 周杰伦 on 2018/4/2. 9 | */ 10 | public class 数字的所有不同组合 { 11 | public static void main(String[] args) { 12 | int n = 4,k = 2; 13 | System.out.println(Arrays.toString(combine(n,k).toArray())); 14 | } 15 | public static List> combine(int n, int k) { 16 | List arr = new ArrayList<>(); 17 | List> list = new ArrayList<>(); 18 | backTracking(arr,1, n, k, list); 19 | return list; 20 | } 21 | public static void backTracking(List arr,int left, int n, int k, List> list) { 22 | if (arr.size() == k) { 23 | list.add(new ArrayList(arr)); 24 | return; 25 | } 26 | for (int i = left;i <= n;i ++) { 27 | arr.add(i); 28 | backTracking(arr, i + 1, n, k, list); 29 | arr.remove(arr.size() - 1); 30 | } 31 | return; 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/BackTracking/数字键打出字母组合.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/1. 8 | */ 9 | public class 数字键打出字母组合 { 10 | public List letterCombinations(String digits) { 11 | if (digits == null || digits.equals(""))return new ArrayList<>(); 12 | List list = new ArrayList<>(); 13 | combineStr("",0,digits,list); 14 | return list; 15 | } 16 | public void combineStr(String prefix, int offset, String digits, Listret) { 17 | if (offset == digits.length()) { 18 | ret.add(prefix); 19 | return; 20 | } 21 | String letters = KEYS[digits.charAt(offset) - '0']; 22 | char[] arr = letters.toCharArray(); 23 | for (char c : arr) { 24 | combineStr(prefix + c,offset + 1,digits, ret); 25 | } 26 | } 27 | private static final String[] KEYS = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/BackTracking/数独.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/2. 5 | */ 6 | public class 数独 { 7 | } 8 | -------------------------------------------------------------------------------- /src/BackTracking/数组的所有子集.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by 周杰伦 on 2018/4/2. 9 | */ 10 | public class 数组的所有子集 { 11 | public static void main(String[] args) { 12 | int []a = {1,2,3}; 13 | System.out.println(Arrays.toString(subsets(a).toArray())); 14 | } 15 | 16 | public static List> subsets(int[] nums) { 17 | int m = nums.length; 18 | Arrays.sort(nums); 19 | List> list = new ArrayList<>(); 20 | ArrayList arr = new ArrayList<>(); 21 | for (int i = 1 ;i <= nums.length;i ++) { 22 | backTracking(arr, nums,0, i, list); 23 | } 24 | list.add(new ArrayList<>()); 25 | return list; 26 | } 27 | public static void backTracking(ArrayList arr, int []nums, int left , int len, List> list) { 28 | if (arr.size() == len) { 29 | list.add(new ArrayList<>(arr)); 30 | return; 31 | } 32 | for (int i = left;i < nums.length && i < nums.length;i ++) { 33 | arr.add(nums[i]); 34 | backTracking(arr, nums, i + 1,len,list); 35 | arr.remove(arr.size()-1); 36 | } 37 | 38 | return; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/BackTracking/数组的所有子集2.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by 周杰伦 on 2018/4/2. 9 | */ 10 | public class 数组的所有子集2 { 11 | public static void main(String[] args) { 12 | int []a = {1,2,2}; 13 | System.out.println(Arrays.toString(subsetsWithDup(a).toArray())); 14 | } 15 | 16 | public static List> subsetsWithDup(int[] nums) { 17 | int m = nums.length; 18 | Arrays.sort(nums); 19 | List> list = new ArrayList<>(); 20 | ArrayList arr = new ArrayList<>(); 21 | for (int i = 1 ;i <= nums.length;i ++) { 22 | backTracking(arr, nums,0, i, list); 23 | } 24 | list.add(new ArrayList<>()); 25 | return list; 26 | } 27 | public static void backTracking(ArrayList arr, int []nums, int left , int len, List> list) { 28 | if (arr.size() == len) { 29 | if (!list.contains(arr)) { 30 | list.add(new ArrayList<>(arr)); 31 | } 32 | return; 33 | } 34 | for (int i = left;i < nums.length && i < nums.length;i ++) { 35 | arr.add(nums[i]); 36 | backTracking(arr, nums, i + 1,len,list); 37 | arr.remove(arr.size()-1); 38 | } 39 | 40 | return; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/BackTracking/矩阵查找单词.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/1. 5 | */ 6 | public class 矩阵查找单词 { 7 | public static void main(String[] args) { 8 | char [][]a = {{'a','b'}}; 9 | String b = "ba"; 10 | System.out.println(b.charAt(0)); 11 | System.out.println(b.charAt(0) == a[0][1]); 12 | System.out.println(exist(a,b)); 13 | } 14 | public static boolean exist(char[][] board, String word) { 15 | boolean flag = false; 16 | int m = board.length; 17 | int n = board[0].length; 18 | int [][]visit = new int[m][n]; 19 | for (int i = 0;i < m;i ++) { 20 | for (int j = 0; j < n; j++) { 21 | if (board[i][j] == word.charAt(0)) { 22 | if (find(board, word, i, j, visit, 0)) { 23 | return true; 24 | } 25 | } 26 | } 27 | } 28 | return flag; 29 | 30 | } 31 | public static boolean find(char[][]board, String word, int i,int j,int[][]visit, int offset) 32 | { 33 | if (offset == word.length()) { 34 | return true; 35 | } 36 | if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || 37 | word.charAt(offset) != board[i][j] || visit[i][j] == 1) { 38 | return false; 39 | } 40 | 41 | visit[i][j] = 1; 42 | boolean flag = find(board, word, i + 1, j, visit, offset + 1) 43 | ||find(board, word, i, j + 1, visit, offset + 1) 44 | ||find(board, word, i - 1, j, visit, offset + 1) 45 | ||find(board, word, i, j - 1, visit, offset + 1); 46 | visit[i][j] = 0; 47 | return flag; 48 | 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/BackTracking/脑洞大开的矩阵查找单词.java: -------------------------------------------------------------------------------- 1 | package BackTracking; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/7/20. 5 | */ 6 | public class 脑洞大开的矩阵查找单词 { 7 | 8 | static class StopMsgException extends RuntimeException { 9 | 10 | } 11 | 12 | static boolean flag; 13 | 14 | public boolean exist(char[][] board, String word) { 15 | if (word.equals("")) { 16 | return true; 17 | } 18 | int[][] visit = new int[board.length][board[0].length]; 19 | flag = false; 20 | try { 21 | for (int i = 0; i < board.length; i++) { 22 | for (int j = 0; j < board[0].length; j++) { 23 | if (word.charAt(0) == board[i][j]) { 24 | dfs(board, word, visit, i, j); 25 | } 26 | } 27 | } 28 | } catch (StopMsgException e) { 29 | System.out.println(e); 30 | } 31 | return flag; 32 | } 33 | 34 | public void dfs(char[][] board, String word, int[][] visit, int i, int j) { 35 | if (word.equals("")) { 36 | flag = true; 37 | throw new StopMsgException(); 38 | } 39 | if (i > board.length - 1 || i < 0 || j > board[0].length - 1 || j < 0) { 40 | return; 41 | } 42 | if (visit[i][j] == 1) { 43 | return; 44 | } 45 | 46 | if (word.charAt(0) == board[i][j]) { 47 | visit[i][j] = 1; 48 | dfs(board, word.length() == 1 ? "" : word.substring(1, word.length()), visit, i + 1, j); 49 | dfs(board, word.length() == 1 ? "" : word.substring(1, word.length()), visit, i - 1, j); 50 | dfs(board, word.length() == 1 ? "" : word.substring(1, word.length()), visit, i, j - 1); 51 | dfs(board, word.length() == 1 ? "" : word.substring(1, word.length()), visit, i, j + 1); 52 | visit[i][j] = 0; 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/BinSearch/Sqrt.java: -------------------------------------------------------------------------------- 1 | package BinSearch; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/16. 5 | */ 6 | public class Sqrt { 7 | public static int mySqrt(int x) { 8 | return (int) Math.floor(Math.sqrt(x)); 9 | } 10 | 11 | public static void main(String[] args) { 12 | System.out.println(mySqrt(8)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/BinSearch/arrangeCoins.java: -------------------------------------------------------------------------------- 1 | package BinSearch; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/16. 5 | */ 6 | public class arrangeCoins { 7 | public int arrangeCoins(int n) { 8 | if (n <= 1) { 9 | return n; 10 | } 11 | int rem = n,count = 0; 12 | for(int i = 1;i <= n;i++) { 13 | if(rem >= i) { 14 | rem = rem - i; 15 | count ++; 16 | } 17 | else return count; 18 | } 19 | return count; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BinSearch/singleNonDuplicate.java: -------------------------------------------------------------------------------- 1 | package BinSearch; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/16. 5 | */ 6 | public class singleNonDuplicate { 7 | public static void main(String[] args) { 8 | int []num = {1,1,2,3,3,4,4,8,8}; 9 | System.out.println(singleNonDuplicate(num)); 10 | } 11 | public int singleNonDuplicate1(int[] nums) { 12 | // binary search 13 | int n=nums.length, lo=0, hi=n/2; 14 | while (lo < hi) { 15 | int m = (lo + hi) / 2; 16 | if (nums[2*m]!=nums[2*m+1]) hi = m; 17 | else lo = m+1; 18 | } 19 | return nums[2*lo]; 20 | } 21 | public static int singleNonDuplicate(int[] nums) { 22 | int l = 0,r = nums.length - 1; 23 | if (nums.length <= 2) { 24 | return nums[0]; 25 | } 26 | if (nums[1] != nums[0]) { 27 | return nums[0]; 28 | } 29 | if (nums[nums.length - 1] != nums[nums.length - 2]) { 30 | return nums[nums.length - 1]; 31 | } 32 | while (l <= r) { 33 | int m = l + (r - l)/2; 34 | if (nums[m + 1] != nums[m] && nums[m] != nums[m - 1]) { 35 | return nums[m]; 36 | } 37 | if (m - 1 >= 0 && nums[m] == nums[m - 1]) { 38 | r = m - 1; 39 | }else if (m + 1 < nums.length && nums[m] == nums[m + 1]) { 40 | l = m + 1; 41 | }else { 42 | return nums[m]; 43 | } 44 | } 45 | return nums[l]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/DFS/二叉树所有路径.java: -------------------------------------------------------------------------------- 1 | package DFS; 2 | 3 | import ADT.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by 周杰伦 on 2018/3/31. 10 | */ 11 | public class 二叉树所有路径 { 12 | 13 | public List binaryTreePaths(TreeNode root) { 14 | List list = new ArrayList<>(); 15 | if (root == null)return list; 16 | String str = ""; 17 | return dfs(root, list, str); 18 | } 19 | public List dfs (TreeNode root, List list, String str) { 20 | if (root == null) return null; 21 | if (root.left == null && root.right == null) { 22 | str += root.val; 23 | }else { 24 | str += root.val + "->"; 25 | } 26 | 27 | dfs(root.left, list, str); 28 | dfs(root.right, list, str); 29 | if (root.left == null && root.right == null) { 30 | list.add(str); 31 | } 32 | str = ""; 33 | return list; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/DFS/图的连通分量个数.java: -------------------------------------------------------------------------------- 1 | package DFS; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/3/30. 7 | */ 8 | public class 图的连通分量个数 { 9 | static int count = 0; 10 | public int findCircleNum(int[][] M) { 11 | count = 0; 12 | int []visit = new int[M.length]; 13 | Arrays.fill(visit, 0); 14 | for (int i = 0;i < M.length;i ++) { 15 | if (visit[i] == 0) { 16 | dfs(M, i, visit); 17 | count ++; 18 | } 19 | } 20 | 21 | return count; 22 | } 23 | public void dfs (int [][]M, int j, int []visit) { 24 | for (int i = 0;i < M.length;i ++) { 25 | if (M[j][i] == 1 && visit[i] == 0) { 26 | visit[i] = 1; 27 | dfs(M, i, visit); 28 | } 29 | } 30 | } 31 | 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/DFS/太平洋和大西洋灌水.java: -------------------------------------------------------------------------------- 1 | package DFS; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/3/31. 8 | * 逆向思维。 9 | * 先把靠着大西洋的两条边灌满大西洋水。 10 | * 再把靠着太平洋的两条边灌满太平洋水。 11 | * 然后往依次灌水,wet和visit表示已灌水和已遍历。 12 | * 最后判断两种水都有的点极为所求。 13 | * 妙啊,妙啊。 14 | */ 15 | public class 太平洋和大西洋灌水 { 16 | public List pacificAtlantic(int[][] matrix) { 17 | List result = new ArrayList(); 18 | if(matrix.length == 0 || matrix[0].length == 0) return result; 19 | boolean[][] pacific = new boolean[matrix.length][matrix[0].length]; // the pacific boolean table 20 | boolean[][] atlantic = new boolean[matrix.length][matrix[0].length]; // the atlantic booean table 21 | //initially, all the top and left cells are flooded with pacific water 22 | //and all the right and bottom cells are flooded with atlantic water 23 | for(int i = 0; i < matrix.length; i++){ 24 | pacific[i][0] = true; 25 | atlantic[i][matrix[0].length-1] = true; 26 | } 27 | for(int i = 0; i < matrix[0].length; i++){ 28 | pacific[0][i] = true; 29 | atlantic[matrix.length-1][i] = true; 30 | } 31 | //we go around the matrix and try to flood the matrix from 4 side. 32 | for(int i = 0; i < matrix.length; i++){ 33 | boolean[][] pacificVisited = new boolean[matrix.length][matrix[0].length]; 34 | boolean[][] atlanticVisited = new boolean[matrix.length][matrix[0].length]; 35 | water(pacific, pacificVisited, matrix, i,0); 36 | water(atlantic, atlanticVisited, matrix, i, matrix[0].length - 1); 37 | } 38 | for(int i = 0; i < matrix[0].length; i++){ 39 | boolean[][] pacificVisited = new boolean[matrix.length][matrix[0].length]; 40 | boolean[][] atlanticVisited = new boolean[matrix.length][matrix[0].length]; 41 | water(pacific, pacificVisited, matrix, 0,i); 42 | water(atlantic, atlanticVisited, matrix, matrix.length - 1, i); 43 | } 44 | //check the shared points among 2 tables 45 | for(int i = 0; i < matrix.length; i++){ 46 | for(int j = 0; j < matrix[0].length; j++){ 47 | if(pacific[i][j] && atlantic[i][j]){ 48 | int[] element = {i,j}; 49 | result.add(element); 50 | } 51 | } 52 | } 53 | return result; 54 | } 55 | //the flood function 56 | private void water(boolean[][] wet, boolean[][] visited, int[][] matrix, int i , int j){ 57 | wet[i][j] = true; 58 | visited[i][j] = true; 59 | int[] x = {0,0,1,-1}; 60 | int[] y = {1,-1,0,0}; 61 | for(int k = 0; k < 4; k++){ 62 | if(i+y[k] >= 0 && i+y[k] < matrix.length && j+x[k] >= 0 && j+x[k] < matrix[0].length 63 | && !visited[i+y[k]][j+x[k]] && matrix[i+y[k]][j+x[k]] >= matrix[i][j]){ 64 | water(wet, visited, matrix, i+y[k], j+x[k]); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/DFS/岛屿的最大面积.java: -------------------------------------------------------------------------------- 1 | package DFS; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/7/18. 5 | */ 6 | public class 岛屿的最大面积 { 7 | public static void main(String[] args) { 8 | int [][]a = {{1,1,0,0,0},{1,1,0,0,0},{0,0,0,1,1},{0,0,0,1,1}}; 9 | System.out.println(maxAreaOfIsland(a)); 10 | } 11 | public static int maxAreaOfIsland(int[][] grid) { 12 | int [][]visit = new int[grid.length][grid[0].length]; 13 | int max = 0; 14 | for (int i = 0;i < grid.length;i ++) { 15 | for (int j = 0;j < grid[0].length;j ++) { 16 | if (grid[i][j] == 1) { 17 | max = Math.max(max, dfs(grid, i, j, visit, 0)); 18 | } 19 | } 20 | } 21 | return max; 22 | } 23 | 24 | public static int dfs(int [][]grid, int x, int y, int [][]visit, int count) { 25 | if (x < 0 || x > grid.length - 1 || y < 0 || y > grid[0].length - 1) { 26 | return count; 27 | } 28 | if (visit[x][y] == 1 || grid[x][y] == 0) { 29 | return count; 30 | } 31 | 32 | visit[x][y] = 1; 33 | count ++; 34 | 35 | count += dfs(grid, x + 1, y, visit, 0); 36 | count += dfs(grid, x - 1, y, visit, 0); 37 | count += dfs(grid, x, y + 1, visit, 0); 38 | count += dfs(grid, x, y - 1, visit, 0); 39 | return count; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/DFS/改变一组数的正负号使得它们的和为一给定数.java: -------------------------------------------------------------------------------- 1 | package DFS; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/8. 5 | */ 6 | public class 改变一组数的正负号使得它们的和为一给定数 { 7 | static int count = 0; 8 | public static void main(String[] args) { 9 | int []a = {1, 1, 1, 1, 1}; 10 | int S = 3; 11 | System.out.println(findTargetSumWays(a,S)); 12 | } 13 | public static int findTargetSumWays(int[] nums, int S) { 14 | count = 0; 15 | dfs(0,nums,0,S); 16 | return count; 17 | } 18 | public static void dfs(int cur,int []nums, int sum, int S) { 19 | if (sum == S && cur == nums.length) { 20 | count += 1; 21 | } 22 | if (cur >= nums.length) return; 23 | dfs(cur + 1,nums,sum + nums[cur],S); 24 | dfs(cur + 1,nums,sum + nums[cur] * (-1),S); 25 | return; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DFS/朋友圈.java: -------------------------------------------------------------------------------- 1 | package DFS; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/7/19. 5 | */ 6 | public class 朋友圈 { 7 | public static void main(String[] args) { 8 | int [][]a = {{1,1,0}, {1,1,0}, {0,0,1}}; 9 | System.out.println(findCircleNum(a)); 10 | } 11 | private static int n; 12 | 13 | public static int findCircleNum(int[][] M) { 14 | n = M.length; 15 | int circleNum = 0; 16 | boolean[] hasVisited = new boolean[n]; 17 | for (int i = 0; i < n; i ++) { 18 | if (!hasVisited[i]) { 19 | dfs(M, i, hasVisited); 20 | circleNum++; 21 | } 22 | } 23 | return circleNum; 24 | } 25 | 26 | private static void dfs(int[][] M, int i, boolean[] hasVisited) { 27 | hasVisited[i] = true; 28 | for (int k = 0; k < n; k++) { 29 | if (M[i][k] == 1 && !hasVisited[k]) { 30 | dfs(M, k, hasVisited); 31 | } 32 | } 33 | } 34 | // private static int n; 35 | // public static int findCircleNum(int[][] M) { 36 | // n = M.length; 37 | // int cnt = 0 ; 38 | // int []visit = new int[n]; 39 | // for (int i = 0;i < M.length;i ++) { 40 | // if(visit[i] == 0) { 41 | // dfs(M, visit, i); 42 | // cnt ++; 43 | // } 44 | // } 45 | // return cnt; 46 | // } 47 | // public static void dfs(int[][]M, int[] visit, int i) { 48 | // visit[i] = 1; 49 | // for (int j = 0;j < M.length;j ++) { 50 | // if(visit[j] == 0 && M[i][j] == 1) { 51 | // dfs(M, visit, i); 52 | // } 53 | // } 54 | // } 55 | } 56 | -------------------------------------------------------------------------------- /src/DFS/查找最大的连通面积.java: -------------------------------------------------------------------------------- 1 | package DFS; 2 | 3 | import java.util.Arrays; 4 | import java.util.Stack; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/3/30. 8 | */ 9 | public class 查找最大的连通面积 { 10 | public static void main(String[] args) { 11 | int [][]a = {{0,1},{1,1}}; 12 | System.out.println(maxAreaOfIsland(a)); 13 | } 14 | static int max = 0; 15 | static int count = 0; 16 | public static int maxAreaOfIsland(int[][] grid) { 17 | max = 0; 18 | count = 0; 19 | if (grid == null)return 0; 20 | int m = grid.length; 21 | int n = grid[0].length; 22 | int [][]visit = new int[m][n]; 23 | for (int i = 0;i < visit.length;i ++) { 24 | Arrays.fill(visit[i],0); 25 | } 26 | 27 | for (int i = 0;i < m;i ++) { 28 | for (int j = 0;j < n;j ++) { 29 | count = 0; 30 | if (grid[i][j] == 1) { 31 | dfs(grid, visit, i, j); 32 | } 33 | if (count > max) max = count; 34 | } 35 | } 36 | return max; 37 | } 38 | public static void dfs(int [][]grid,int [][]visit, int x, int y) { 39 | if (x < 0 || y < 0 || x >= grid.length || y >= grid[0].length ||grid[x][y] == 0 || visit[x][y] == 1) return; 40 | 41 | visit[x][y] = 1; 42 | count ++; 43 | dfs(grid,visit,x + 1,y); 44 | dfs(grid,visit,x,y + 1); 45 | dfs(grid,visit,x - 1,y); 46 | dfs(grid,visit,x ,y - 1); 47 | return; 48 | } 49 | 50 | //非递归写法 51 | // class Pos{ 52 | // int x; 53 | // int y; 54 | // int count; 55 | // 56 | // public Pos(int x, int y, int count) { 57 | // this.x = x; 58 | // this.y = y; 59 | // this.count = count; 60 | // } 61 | // } 62 | // public int stack(int [][]grid,int [][]visit, int x, int y) { 63 | // Stack stack = new Stack<>(); 64 | // stack.push(new Pos(x, y, 0)); 65 | // int [][]pos = {{0,1}, {0, -1}, {1, 0}, {-1, 0}}; 66 | // while (!stack.isEmpty()) { 67 | // Pos init = stack.peek(); 68 | // for (int i = 0; i < pos.length; i++) { 69 | // int x0 = x + pos[i][0]; 70 | // int y0 = y + pos[i][1]; 71 | // if (visit[x0][y0] == 0 && grid[x0][y0] == 1) { 72 | // stack.push(new Pos(x0, y0, init.count + 1)); 73 | // break; 74 | // } 75 | // } 76 | // stack.pop(); 77 | // } 78 | // } 79 | } 80 | -------------------------------------------------------------------------------- /src/DFS/矩阵中的连通区域数量.java: -------------------------------------------------------------------------------- 1 | package DFS; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/3/31. 7 | */ 8 | public class 矩阵中的连通区域数量 { 9 | public static void main(String[] args) { 10 | 11 | } 12 | static int count = 0; 13 | public int numIslands(char[][] grid) { 14 | if (grid == null || grid.length == 0)return 0; 15 | count = 0; 16 | int m = grid.length; 17 | int n = grid[0].length; 18 | int [][]visit = new int[m][n]; 19 | for (int i = 0;i < visit.length;i ++) { 20 | Arrays.fill(visit[i],0); 21 | } 22 | for (int i = 0;i < m;i ++) { 23 | for (int j = 0;j < n;j ++) { 24 | if (grid[i][j] == '1' && visit[i][j] == 0) { 25 | count ++; 26 | dfs(grid,visit, i, j); 27 | } 28 | } 29 | } 30 | return count; 31 | } 32 | public void dfs(char[][] grid,int [][]visit, int x,int y ) { 33 | if (x < 0 || y < 0 || x >= grid.length || y >= grid[0].length ||grid[x][y] == '0' || visit[x][y] == 1) return; 34 | visit[x][y] = 1; 35 | dfs(grid,visit,x + 1,y); 36 | dfs(grid,visit,x,y + 1); 37 | dfs(grid,visit,x - 1,y); 38 | dfs(grid,visit,x ,y - 1); 39 | return; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/DFS/被围绕的区域.java: -------------------------------------------------------------------------------- 1 | package DFS; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/7/19. 8 | */ 9 | public class 被围绕的区域 { 10 | private int m, n; 11 | private int[][] matrix; 12 | private int[][] direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; 13 | 14 | public List pacificAtlantic(int[][] matrix) { 15 | List ret = new ArrayList<>(); 16 | if (matrix == null || matrix.length == 0) { 17 | return ret; 18 | } 19 | 20 | m = matrix.length; 21 | n = matrix[0].length; 22 | this.matrix = matrix; 23 | boolean[][] canReachP = new boolean[m][n]; 24 | boolean[][] canReachA = new boolean[m][n]; 25 | 26 | for (int i = 0; i < m; i++) { 27 | dfs(i, 0, canReachP); 28 | dfs(i, n - 1, canReachA); 29 | } 30 | for (int i = 0; i < n; i++) { 31 | dfs(0, i, canReachP); 32 | dfs(m - 1, i, canReachA); 33 | } 34 | 35 | for (int i = 0; i < m; i++) { 36 | for (int j = 0; j < n; j++) { 37 | if (canReachP[i][j] && canReachA[i][j]) { 38 | ret.add(new int[]{i, j}); 39 | } 40 | } 41 | } 42 | 43 | return ret; 44 | } 45 | 46 | private void dfs(int r, int c, boolean[][] canReach) { 47 | if (canReach[r][c]) { 48 | return; 49 | } 50 | canReach[r][c] = true; 51 | for (int[] d : direction) { 52 | int nextR = d[0] + r; 53 | int nextC = d[1] + c; 54 | if (nextR < 0 || nextR >= m || nextC < 0 || nextC >= n 55 | || matrix[r][c] > matrix[nextR][nextC]) { 56 | 57 | continue; 58 | } 59 | dfs(nextR, nextC, canReach); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/DP/信件排错.java: -------------------------------------------------------------------------------- 1 | package DP; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/4. 5 | * 信件错排 6 | 7 | 题目描述:有 N 个 信 和 信封,它们被打乱,求错误装信的方式数量。 8 | 9 | 定义一个数组 dp 存储错误方式数量,dp[i] 表示前 i 个信和信封的错误方式数量。 10 | 假设第 i 个信装到第 j 个信封里面,而第 j 个信装到第 k 个信封里面。 11 | 根据 i 和 k 是否相等,有两种情况: 12 | ① i==k,交换 i 和 k 的信后,它们的信和信封在正确的位置,但是其余 i-2 封信有 dp[i-2] 种错误装信的方式。 13 | 由于 j 有 i-1 种取值,因此共有 (i-1)*dp[i-2] 种错误装信方式。 14 | ② i != k,交换 i 和 j 的信后,第 i 个信和信封在正确的位置,其余 i-1 封信有 dp[i-1] 种错误装信方式。 15 | 由于 j 有 i-1 种取值,因此共有 (n-1)*dp[i-1] 种错误装信方式。 16 | 综上所述,错误装信数量方式数量为: 17 | 18 | 19 | 20 | dp[N] 即为所求。 21 | 22 | 和上楼梯问题一样,dp[i] 只与 dp[i-1] 和 dp[i-2] 有关,因此也可以只用两个变量来存储 dp[i-1] 和 dp[i-2]。 23 | 24 | 25 | */ 26 | public class 信件排错 { 27 | } 28 | -------------------------------------------------------------------------------- /src/DP/分割整数/分割整数的最大乘积自写.java: -------------------------------------------------------------------------------- 1 | package DP.分割整数; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/9. 5 | */ 6 | public class 分割整数的最大乘积自写 { 7 | // 2 = 1+1 3 = 1+2 4=2+2 5=2+3 6=3+3 8 | public static void main(String[] args) { 9 | System.out.println(integerBreak(10)); 10 | } 11 | public static int integerBreak(int n) { 12 | if (n == 1 || n == 0)return 0; 13 | int []dp = new int[n + 1]; 14 | dp[0] = 0; 15 | dp[1] = 1; 16 | dp[2] = 1; 17 | for (int i = 3;i <= n;i ++) { 18 | for (int j = 1;j < i;j ++ ) { 19 | dp[i] = Math.max(dp[i],dp[j] * (i - j)); 20 | if ((i-j) * j > dp[i] ) dp[i] = (i - j) * j; 21 | } 22 | } 23 | return dp[n]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/DP/分割整数/按平方数来分割整数.java: -------------------------------------------------------------------------------- 1 | package DP.分割整数; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/3. 5 | */ 6 | public class 按平方数来分割整数 { 7 | public static void main(String[] args) { 8 | System.out.println(numSquares(12)); 9 | System.out.println(numSquares(13)); 10 | 11 | } 12 | //dp[1] = 1; 13 | //dp[2] = 2; 14 | //dp[3] = 3; 15 | //dp[4] = 1;dp[5] = 2 dp[6] = 3 dp[7]=4 dp[8]=2 dp[9]=3 dp[10]=2 dp[11]=3 dp[12] = 3 16 | //dp[i] = dp[i-j] + per 17 | //dp[i] = dp[i-1] + 1;huozhe dp[i-j] + which i-j = perfect 18 | public static int numSquares(int n) { 19 | int []dp = new int[n + 1]; 20 | dp[1] = 1; 21 | dp[0] = 0; 22 | for (int k = 2;k <= n;k ++) { 23 | dp[k] = k; 24 | } 25 | 26 | for (int i = 2;i <= n;i ++) { 27 | int j = 1; 28 | int min = dp[i]; 29 | while (i - j*j >= 0 ) { 30 | min = Math.min(min,dp[i - j*j] + 1); 31 | j ++; 32 | } 33 | dp[i] = min; 34 | } 35 | 36 | return dp[n]; 37 | } 38 | public static boolean isPerfect(int n) { 39 | if (Math.pow(n,0.5) - Math.ceil(Math.pow(n,0.5)) == 0) { 40 | return true; 41 | } 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/DP/分割整数/按平方数来分割整数自写.java: -------------------------------------------------------------------------------- 1 | package DP.分割整数; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/9. 5 | */ 6 | public class 按平方数来分割整数自写 { 7 | public static void main(String[] args) { 8 | System.out.println(numSquares(12)); 9 | } 10 | public static int numSquares(int n) { 11 | int []dp = new int[n + 1]; 12 | dp[1] = 1; 13 | for (int i = 2;i <= n;i ++) { 14 | //默认等于前一位+1 15 | dp[i] = dp[i - 1] + 1; 16 | if (isSquare(i)) { 17 | dp[i] = 1; 18 | continue; 19 | } 20 | //当差为平方数时直接 等于其+1即可。这样的时间复杂度大大降低。 21 | //为onlogn.否则是on2不符合要求 22 | for (int j = 1;j * j < i;j ++) { 23 | dp[i] = Math.min(dp[i], dp[i - j * j] + 1); 24 | } 25 | } 26 | return dp[n]; 27 | } 28 | public static boolean isSquare(int n) { 29 | if (Math.ceil(Math.pow(n,0.5)) == Math.pow(n,0.5)) { 30 | return true; 31 | } 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/DP/字符串编辑/修改一个字符串为另一个字符串.java: -------------------------------------------------------------------------------- 1 | package DP.字符串编辑; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/9. 5 | */ 6 | public class 修改一个字符串为另一个字符串 { 7 | public int minDistance(String word1, String word2) { 8 | if (word1.equals("") && word2.equals(""))return 0; 9 | int m = word1.length(); 10 | int n = word2.length(); 11 | //把word1的前i个字符变成word2的前j个字符。 12 | int [][]dp = new int[m + 1][n + 1]; 13 | for (int i = 1;i <= m;i ++) { 14 | dp[i][0] = i; 15 | } 16 | for (int j = 1;j <= n;j ++) { 17 | dp[0][j] = j; 18 | } 19 | dp[0][0] = 0; 20 | for (int i = 1;i <= m;i ++) { 21 | for (int j = 1;j <= n;j ++) { 22 | int c1 = dp[i][j - 1] + 1; 23 | int c2 = dp[i - 1][j] + 1; 24 | int c3 = dp[i - 1][j - 1] + 1; 25 | if (word1.charAt(i - 1) == word2.charAt(j - 1)) { 26 | c3 = dp[i - 1][j - 1]; 27 | } 28 | int min = Math.min(Math.min(c1, c2), c3); 29 | dp[i][j] = min; 30 | } 31 | } 32 | return dp[m][n]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/DP/字符串编辑/删除两个字符串的字符使它们相等.java: -------------------------------------------------------------------------------- 1 | package DP.字符串编辑; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/9. 5 | */ 6 | public class 删除两个字符串的字符使它们相等 { 7 | public static void main(String[] args) { 8 | String a = "eat"; 9 | String b = "sea"; 10 | System.out.println(minDistance(a, b)); 11 | System.out.println(LCS(a, b)); 12 | } 13 | public static int minDistance(String word1, String word2) { 14 | int len = LCS(word1, word2); 15 | return word1.length() + word2.length() - len - len; 16 | } 17 | public static int LCS(String a, String b) { 18 | if (a.equals("") || b.equals(""))return 0; 19 | //a的前i个字符与b的前j个字符的公共子序列长度 20 | int [][]dp = new int[a.length() + 1][b.length() + 1]; 21 | for (int i = 0;i < dp.length;i ++) { 22 | dp[i][0] = 0; 23 | } 24 | for (int i = 0;i < dp[0].length;i ++) { 25 | dp[0][i] = 0; 26 | } 27 | for (int i = 1;i <= a.length();i ++) { 28 | for (int j = 1;j <= b.length();j ++) { 29 | if (a.charAt(i - 1) == b.charAt(j - 1)) { 30 | dp[i][j] = dp[i - 1][j - 1] + 1; 31 | }else { 32 | dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); 33 | } 34 | } 35 | } 36 | return dp[a.length()][b.length()]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/DP/字符串编辑/复制粘贴字符.java: -------------------------------------------------------------------------------- 1 | package DP.字符串编辑; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/11. 5 | */ 6 | public class 复制粘贴字符 { 7 | public static void main(String[] args) { 8 | System.out.println(minSteps(3)); 9 | System.out.println(minSteps(4)); 10 | System.out.println(minSteps(5)); 11 | System.out.println(minSteps(6)); 12 | System.out.println(minSteps(7)); 13 | System.out.println(minSteps(8)); 14 | } 15 | public static int minSteps(int n) { 16 | if (n == 1) return 0; 17 | int []dp = new int[n + 1]; 18 | dp[1] = 1; 19 | //dp[2] = 2; 20 | //dp[3] = 3; 21 | //dp[4] = 4; dp[5] = 5;dp[6] = 5;dp[7] = 7;dp[8] = 6; 22 | 23 | for (int i = 2;i <= n;i ++) { 24 | dp[i] = i; 25 | for (int j = 1;j < i;j ++) { 26 | if (i % j == 0) { 27 | dp[i] = Math.min(dp[i], dp[j] + ((i/j))); 28 | } 29 | } 30 | } 31 | return dp[n]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/DP/字符串编辑/字符串复制粘贴.java: -------------------------------------------------------------------------------- 1 | package DP.字符串编辑; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/10. 5 | */ 6 | public class 字符串复制粘贴 { 7 | public int minSteps(int n) { 8 | int[] dp = new int[n+1]; 9 | 10 | for (int i = 2; i <= n; i++) { 11 | dp[i] = i; 12 | for (int j = i-1; j > 1; j--) { 13 | if (i % j == 0) { 14 | dp[i] = dp[j] + (i/j); 15 | break; 16 | } 17 | 18 | } 19 | } 20 | return dp[n]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DP/强盗在环形街区抢劫.java: -------------------------------------------------------------------------------- 1 | package DP; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/4. 5 | */ 6 | public class 强盗在环形街区抢劫 { 7 | public static void main(String[] args) { 8 | int []a = {1,2}; 9 | int []b = {1,2,3}; 10 | int []c = {1,3,2,4}; 11 | int []d = {6,4,2,5,9}; 12 | System.out.println(rob(a)); 13 | System.out.println(rob(b)); 14 | System.out.println(rob(c)); 15 | System.out.println(rob(d)); 16 | } 17 | public static int rob(int[] nums) { 18 | if (nums == null || nums.length == 0) return 0; 19 | if (nums.length == 1)return nums[0]; 20 | if (nums.length == 2)return nums[0] > nums[1] ? nums[0] : nums[1]; 21 | int []dp = new int[nums.length + 1]; 22 | //dp代表最右只抢到第n家时的总钱数。 23 | //如果抢了第一家 24 | dp[1] = nums[0]; 25 | dp[2] = nums[0] > nums[1] ? nums[0] : nums[1]; 26 | for (int i = 3;i < nums.length;i ++) { 27 | dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]); 28 | } 29 | int max = dp[nums.length - 1]; 30 | //如果不抢第一家 31 | dp[1] = 0; 32 | dp[2] = nums[1]; 33 | for (int i = 3;i <= nums.length;i ++) { 34 | dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]); 35 | } 36 | 37 | if (dp[nums.length] > max)max = dp[nums.length]; 38 | return max; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/DP/强盗抢劫.java: -------------------------------------------------------------------------------- 1 | package DP; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/4. 5 | */ 6 | public class 强盗抢劫 { 7 | public static void main(String[] args) { 8 | int []a = {1,3,5,7,2}; 9 | int []b = {2,6,9,1}; 10 | System.out.println(rob(a)); 11 | System.out.println(rob(b)); 12 | } 13 | public static int rob(int[] nums) { 14 | if (nums == null || nums.length == 0) return 0; 15 | if (nums.length == 1)return nums[0]; 16 | if (nums.length == 2)return nums[0] > nums[1] ? nums[0] : nums[1]; 17 | int []dp = new int[nums.length + 1]; 18 | //dp代表最右只抢到第n家时的总钱数。 19 | dp[1] = nums[0]; 20 | dp[2] = nums[0] > nums[1] ? nums[0] : nums[1]; 21 | for (int i = 3;i <= nums.length;i ++) { 22 | dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]); 23 | } 24 | return dp[nums.length]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/DP/数组区间/子数组最大的和.java: -------------------------------------------------------------------------------- 1 | package DP.数组区间; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/9. 5 | */ 6 | public class 子数组最大的和 { 7 | public static void main(String[] args) { 8 | int []a = {-2,1,-3,4,-1,2,1,-5,4}; 9 | System.out.println(maxSubArray(a)); 10 | } 11 | public static int maxSubArray(int[] nums) { 12 | int []dp = new int[nums.length + 1]; 13 | dp[0] = 0; 14 | for (int i = 1;i <= nums.length;i ++) { 15 | dp[i] = Math.max(dp[i - 1] + nums[i - 1],nums[i - 1]); 16 | } 17 | int max = dp[1]; 18 | for (int i = 1;i <= nums.length;i ++) { 19 | if (dp[i] > max)max = dp[i]; 20 | } 21 | return max; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DP/数组区间/数组中等差递增子区间的个数.java: -------------------------------------------------------------------------------- 1 | package DP.数组区间; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/9. 5 | */ 6 | public class 数组中等差递增子区间的个数 { 7 | //首先找规律。3个等差数字 dp[3] = 1 .dp[4] = 4个数和后面3个数=2. 8 | //dp[5] = 前五个数 2345 345 = 3.可得dp[i] = dp[i - 1] + 1; 9 | public static void main(String[] args) { 10 | 11 | } 12 | public int numberOfArithmeticSlices(int[] A) { 13 | int []dp = new int[A.length]; 14 | for (int i = 2;i < A.length;i ++) { 15 | if (A[i - 1] - A[i - 2] == A[i] - A[i - 1]) { 16 | //此处的初值为1,接下来的推导都是正确的。 17 | dp[i] = dp[i - 1] + 1; 18 | } 19 | } 20 | int res = 0; 21 | //算出总的方法数。妙啊 22 | for (int cnt : dp) { 23 | res += cnt; 24 | } 25 | return res; 26 | } 27 | 28 | // dfs行不通 29 | // static int count = 0; 30 | // public int numberOfArithmeticSlices(int[] A) { 31 | // for (int i = 2;i < A.length;i ++) { 32 | // dfs(A, i,true, 0); 33 | // } 34 | // return count; 35 | // } 36 | // public void dfs(int []A, int cur, boolean flag, int diff) { 37 | // if (flag && cur <= A.length) { 38 | // count ++; 39 | // return; 40 | // } 41 | // if (A[cur + 1] - A[cur] == A[cur + 2] - A[cur + 1] ) { 42 | // flag = true; 43 | // diff = A[cur + 2] - A[cur + 1] 44 | // } 45 | // } 46 | } 47 | -------------------------------------------------------------------------------- /src/DP/数组区间/数组区间和.java: -------------------------------------------------------------------------------- 1 | package DP.数组区间; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/9. 5 | */ 6 | public class 数组区间和 { 7 | class NumArray { 8 | private int[] sums; 9 | 10 | // 求区间 i ~ j 的和,可以转换为 sum[j] - sum[i-1],其中 sum[i] 为 0 ~ i 的和。 11 | public NumArray(int[] nums) { 12 | sums = new int[nums.length]; 13 | for (int i = 0; i < nums.length; i++) { 14 | sums[i] = i == 0 ? nums[0] : sums[i - 1] + nums[i]; 15 | } 16 | } 17 | 18 | public int sumRange(int i, int j) { 19 | return i == 0 ? sums[j] : sums[j] - sums[i - 1]; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DP/最长摆动子序列_双数组.java: -------------------------------------------------------------------------------- 1 | package DP; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/4. 5 | */ 6 | public class 最长摆动子序列_双数组 { 7 | public static void main(String[] args) { 8 | int []a = {1,7,4,9,2,5}; 9 | int []b = {1,17,5,10,13,15,10,5,16,8}; 10 | int []c = {1,2,3,4,5,6,7,8,9}; 11 | int []d = {0,0,0,0,1,0}; 12 | System.out.println(wiggleMaxLength(a)); 13 | System.out.println(wiggleMaxLength(b)); 14 | System.out.println(wiggleMaxLength(c)); 15 | System.out.println(wiggleMaxLength(d)); 16 | 17 | } 18 | public static int wiggleMaxLength(int[] nums) { 19 | if (nums.length == 0)return 0; 20 | int []up = new int[nums.length]; 21 | int []down = new int[nums.length]; 22 | up[0] = 1; 23 | down[0] = 1; 24 | for (int i = 1;i < nums.length;i ++) { 25 | if (nums[i] > nums[i - 1]) { 26 | up[i] = down[i - 1] + 1; 27 | down[i] = down[i - 1]; 28 | }else if (nums[i] < nums[i - 1]) { 29 | down[i] = up[i - 1] + 1; 30 | up[i] = up[i - 1]; 31 | }else { 32 | up[i] = up[i - 1]; 33 | down[i] = down[i - 1]; 34 | } 35 | } 36 | return Math.max(down[nums.length - 1], up[nums.length - 1]); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/DP/母牛生产.java: -------------------------------------------------------------------------------- 1 | package DP; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/4. 5 | * * 母牛生产 6 | 7 | 程序员代码面试指南-P181 8 | 9 | 题目描述:假设农场中成熟的母牛每年都会生 1 头小母牛,并且永远不会死。 10 | 第一年有 1 只小母牛,从第二年开始,母牛开始生小母牛。 11 | 每只小母牛 3 年之后成熟又可以生小母牛。给定整数 N,求 N 年后牛的数量。 12 | 13 | 第 i 年成熟的牛的数量为: 14 | 15 | 16 | */ 17 | 18 | public class 母牛生产 { 19 | } 20 | -------------------------------------------------------------------------------- /src/DP/矩阵路径/爬楼梯方法总数.java: -------------------------------------------------------------------------------- 1 | package DP.矩阵路径; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/4. 5 | */ 6 | public class 爬楼梯方法总数 { 7 | public int climbStairs(int n) { 8 | if (n == 1 || n == 2)return n; 9 | int []dp = new int[n + 1]; 10 | dp[1] = 1; 11 | dp[2] = 2; 12 | for (int i = 3;i <= n;i ++ ) { 13 | dp[i] = dp[i - 1] + dp[i - 2]; 14 | } 15 | return dp[n]; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/DP/矩阵路径/矩阵的总路径数.java: -------------------------------------------------------------------------------- 1 | package DP.矩阵路径; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/4. 5 | */ 6 | public class 矩阵的总路径数 { 7 | public static void main(String[] args) { 8 | 9 | } 10 | public int uniquePaths(int m, int n) { 11 | int [][]dp = new int[m][n]; 12 | for (int i = 0;i < m;i ++) { 13 | dp[i][0] = 1; 14 | } 15 | for (int j = 0;j < n;j ++) { 16 | dp[0][j] = 1; 17 | } 18 | 19 | for (int i = 1;i < m;i ++) { 20 | for (int j = 1;j < n;j ++) { 21 | dp[i][j] = dp[i][j - 1] + dp[i - 1][j]; 22 | } 23 | } 24 | return dp[m - 1][n - 1]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/DP/经典/分割整数的最大乘积.java: -------------------------------------------------------------------------------- 1 | package DP.经典; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/3. 5 | */ 6 | public class 分割整数的最大乘积 { 7 | //2 = 1+1 1 /3 2+1 2/4 2+2 4/5 2+3 6/6 3+3 9 8 | // /7 3 2 2 12/8 = 3+3+2 18/9 = 3+3+3 27/10 = 3+3+4 36 9 | //dp[0] = 0 dp[1] = 0 dp[2] = 1; dp[3] = dp[2] + i - 1 10 | //dp[i] = dp[i-1] 11 | public int integerBreak(int n) { 12 | int []dp = new int[n + 1]; 13 | dp[1] = 0; 14 | //dp[i]代表以以i为结尾的最大乘积。 15 | for (int i = 2;i <=n;i ++) { 16 | for (int j = 1;j < i;j ++) { 17 | //这一部是将n分成i和j两个数,要么取j要么取j分成的数。 18 | //要么取i-j要么取i-j拆分成的数,谁大就取谁。 19 | //再将这两部分相乘。并且dp是从左往右算的,可以保证有序。 20 | dp[i] = Math.max(dp[i],Math.max(j,dp[j])*Math.max(i - j,dp[i - j])); 21 | } 22 | } 23 | return dp[n]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/DP/经典/最长公共子序列.java: -------------------------------------------------------------------------------- 1 | package DP.经典; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/6. 5 | */ 6 | public class 最长公共子序列 { 7 | public int lengthOfLCS(int[] nums1, int[] nums2) { 8 | int n1 = nums1.length, n2 = nums2.length; 9 | int[][] dp = new int[n1 + 1][n2 + 1]; 10 | for (int i = 1; i <= n1; i++) { 11 | for (int j = 1; j <= n2; j++) { 12 | if (nums1[i - 1] == nums2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; 13 | else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); 14 | } 15 | } 16 | return dp[n1][n2]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DP/经典/最长递增子序列.java: -------------------------------------------------------------------------------- 1 | package DP.经典; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/4. 5 | */ 6 | public class 最长递增子序列 { 7 | public static void main(String[] args) { 8 | int []a = {10,9,2,5,3,4}; 9 | int []b = {10, 9, 2, 5, 3, 7, 101, 18}; 10 | int []c = {4,10,4,3,8,9}; 11 | System.out.println(lengthOfLIS(a)); 12 | System.out.println(lengthOfLIS(b)); 13 | System.out.println(lengthOfLIS(c)); 14 | } 15 | public static int lengthOfLIS(int[] nums) { 16 | if (nums == null || nums.length == 0)return 0; 17 | if (nums.length == 1)return 1; 18 | int []dp = new int[nums.length]; 19 | dp[0] = 1; 20 | //int []c = {4,10,4,3,8,9}; 21 | for (int i = 1;i < nums.length;i ++) { 22 | int max = 1; 23 | for (int j = 0;j < i;j ++) { 24 | if (nums[i] > nums[j]) { 25 | max = Math.max(max, dp[j] + 1); 26 | } 27 | dp[i] = max; 28 | } 29 | } 30 | int max = 0; 31 | for (int i = 0;i < nums.length;i ++) { 32 | max = Math.max(dp[i], max); 33 | } 34 | return max; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/DP/经典/矩阵的最小路径和.java: -------------------------------------------------------------------------------- 1 | package DP.经典; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/4. 5 | */ 6 | public class 矩阵的最小路径和 { 7 | public static void main(String[] args) { 8 | 9 | } 10 | public int minPathSum(int[][] grid) { 11 | int m = grid.length; 12 | int n = grid[0].length; 13 | int [][]dp = new int[m][n]; 14 | dp[0][0] = grid[0][0]; 15 | for (int i = 1;i < m;i ++) { 16 | dp[i][0] = dp[i - 1][0] + grid[i][0]; 17 | } 18 | for (int j = 1;j < n;j ++) { 19 | dp[0][j] = dp[0][j - 1] + grid[0][j]; 20 | } 21 | for (int i = 1;i < m;i ++) { 22 | for (int j = 1;j < n;j ++) { 23 | dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; 24 | } 25 | } 26 | return dp[m - 1][n - 1]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/DP/股票买卖/买入和售出股票最大的收益.java: -------------------------------------------------------------------------------- 1 | package DP.股票买卖; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/9. 5 | */ 6 | public class 买入和售出股票最大的收益 { 7 | public static void main(String[] args) { 8 | int []a = {7, 1, 5, 3, 6, 4}; 9 | int []b = {3,2,6,5,0,3}; 10 | System.out.println(maxProfit(a)); 11 | System.out.println(maxProfit(b)); 12 | 13 | } 14 | public static int maxProfit(int[] prices) { 15 | if (prices.length <= 1) { 16 | return 0; 17 | } 18 | int maxProfit = 0; 19 | int lowest = Integer.MAX_VALUE; 20 | for (int v : prices) { 21 | lowest = Math.min(v, lowest); 22 | maxProfit = Math.max(maxProfit, v - lowest); 23 | } 24 | return maxProfit; 25 | } 26 | //时间复杂度过大 27 | // public static int maxProfit(int[] prices) { 28 | // int max = 0; 29 | // for (int i = 1;i < prices.length;i ++) { 30 | // for (int j = 0;j < i;j ++) { 31 | // if (prices[i] - prices[j] > max)max = prices[i] - prices[j]; 32 | // } 33 | // } 34 | // return max; 35 | // } 36 | 37 | //解法太复杂 38 | // public static int maxProfit(int[] prices) { 39 | // if (prices.length == 0)return 0; 40 | // int []dp = new int[prices.length]; 41 | // dp[0] = 0; 42 | // int []mins = new int[prices.length]; 43 | // mins[0] = prices[0]; 44 | // for (int i = 1;i < prices.length;i ++) { 45 | // if (prices[i] < mins[i - 1]) { 46 | // mins[i] = prices[i]; 47 | // }else { 48 | // mins[i] = mins[i - 1]; 49 | // } 50 | // } 51 | // for (int i = 1;i < prices.length;i ++) { 52 | // int min = mins[i]; 53 | // if (prices[i] > min && prices[i] > prices[i - 1]) { 54 | // dp[i] = Math.max(prices[i] - min, dp[i - 1]); 55 | // }else { 56 | // dp[i] = dp[i - 1]; 57 | // } 58 | // } 59 | // return dp[prices.length - 1]; 60 | // } 61 | } 62 | -------------------------------------------------------------------------------- /src/DP/股票买卖/只能进行k次的股票交易.java: -------------------------------------------------------------------------------- 1 | package DP.股票买卖; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/11. 5 | */ 6 | public class 只能进行k次的股票交易 { 7 | } 8 | -------------------------------------------------------------------------------- /src/DP/股票买卖/只能进行两次的股票交易.java: -------------------------------------------------------------------------------- 1 | package DP.股票买卖; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/11. 5 | */ 6 | public class 只能进行两次的股票交易 { 7 | } 8 | -------------------------------------------------------------------------------- /src/DP/股票买卖/需要交易费用的股票交易_多数组.java: -------------------------------------------------------------------------------- 1 | package DP.股票买卖; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/10. 5 | */ 6 | public class 需要交易费用的股票交易_多数组 { 7 | public static void main(String[] args) { 8 | int []a = {1, 3, 2, 8, 4, 9}; 9 | System.out.println(maxProfit(a, 2)); 10 | } 11 | public static int maxProfit(int[] prices, int fee) { 12 | if (prices.length < 2)return 0; 13 | int []sell = new int[prices.length]; 14 | int []buy = new int[prices.length]; 15 | int []hold = new int[prices.length]; 16 | int []empty = new int[prices.length]; 17 | sell[0] = 0; 18 | buy[0] = - prices[0]; 19 | hold[0] = Integer.MIN_VALUE; 20 | empty[0] = 0; 21 | for (int i = 1;i < prices.length;i ++) { 22 | empty[i] = Math.max(empty[i - 1], sell[i - 1]); 23 | buy[i] = Math.max(empty[i - 1],sell[i - 1]) - prices[i]; 24 | hold[i] = Math.max(buy[i - 1], hold[i - 1]); 25 | sell[i] = Math.max(buy[i - 1],hold[i - 1] ) + prices[i] - fee; 26 | } 27 | int max = Math.max(sell[prices.length - 1], empty[prices.length - 1]); 28 | return max; 29 | } 30 | 31 | // public int maxProfit(int[] prices, int fee) { 32 | // if(prices.length <= 1) return 0; 33 | // int[] buy = new int[prices.length]; 34 | // int[] hold = new int[prices.length]; 35 | // int[] skip = new int[prices.length]; 36 | // int[] sell = new int[prices.length]; 37 | // // the moment we buy a stock, our balance should decrease 38 | // buy[0] = 0 - prices[0]; 39 | // // assume if we have stock in the first day, we are still in deficit 40 | // hold[0] = 0 - prices[0]; 41 | // for(int i = 1; i < prices.length; i++){ 42 | // // We can only buy on today if we sold stock 43 | // // or skipped with empty portfolio yesterday 44 | // buy[i] = Math.max(skip[i-1], sell[i-1]) - prices[i]; 45 | // // Can only hold if we bought or already holding stock yesterday 46 | // hold[i] = Math.max(buy[i-1], hold[i-1]); 47 | // // Can skip only if we skipped, or sold stock yesterday 48 | // skip[i] = Math.max(skip[i-1], sell[i-1]); 49 | // // Can sell only if we bought, or held stock yesterday 50 | // sell[i] = Math.max(buy[i-1], hold[i-1]) + prices[i] - fee; 51 | // } 52 | // // Get the max of all the 4 actions on the last day. 53 | // int max = Math.max(buy[prices.length - 1], hold[prices.length - 1]); 54 | // max = Math.max(skip[prices.length - 1], max); 55 | // max = Math.max(sell[prices.length - 1], max); 56 | // return Math.max(max, 0); 57 | // } 58 | } 59 | -------------------------------------------------------------------------------- /src/DP/股票买卖/需要冷却期的股票交易_双数组.java: -------------------------------------------------------------------------------- 1 | package DP.股票买卖; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/9. 5 | */ 6 | public class 需要冷却期的股票交易_双数组 { 7 | public static void main(String[] args) { 8 | int []a = {6,1,3,2,4,7}; 9 | System.out.println(maxProfit(a)); 10 | } 11 | 12 | //错误的解法。 13 | // public static int maxProfit(int[] prices) { 14 | // if (prices.length < 2) return 0; 15 | // int[] sell = new int[prices.length]; 16 | // int []cool = new int[prices.length]; 17 | // int []buy = new int[prices.length]; 18 | // sell[0] = Integer.MIN_VALUE; 19 | // sell[1] = prices[1] - prices[0]; 20 | // cool[0] = Integer.MIN_VALUE; 21 | // cool[1] = Integer.MIN_VALUE; 22 | // buy[0] = - prices[0]; 23 | // buy[1] = - prices[1]; 24 | // for (int i = 2;i < prices.length;i ++) { 25 | // //buy[i] = cool[i - 1] 26 | // buy[i] = cool[i - 1]; 27 | // sell[i] = Math.max(sell[i - 1] + prices[i] - prices[i - 1] ,buy[i - 1] + prices[i]); 28 | // cool[i] = Math.max(cool[i - 1], sell[i - 1]); 29 | // } 30 | // int max = Math.max(sell[prices.length - 1], cool[prices.length - 1]); 31 | // return max; 32 | // } 33 | 34 | 35 | public static int maxProfit(int[] prices) { 36 | if(prices == null || prices.length < 2){ 37 | return 0; 38 | } 39 | int len = prices.length; 40 | int[] sell = new int[len]; //sell[i] means must sell at day i 41 | int[] cooldown = new int[len]; //cooldown[i] means day i is cooldown day 42 | sell[1] = prices[1] - prices[0]; 43 | for(int i = 2; i < prices.length; ++i){ 44 | cooldown[i] = Math.max(sell[i - 1], cooldown[i - 1]); 45 | sell[i] = prices[i] - prices[i - 1] + Math.max(sell[i - 1], cooldown[i - 2]); 46 | } 47 | return Math.max(sell[len - 1], cooldown[len - 1]); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/DP/背包/多维费用的背包.java: -------------------------------------------------------------------------------- 1 | package DP.背包; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/8. 5 | */ 6 | public class 多维费用的背包 { 7 | //是01背包的延伸,费用变成了2维 8 | //接下来的注释是背包问题的一般解法 9 | public static int knapsack2(int W1,int W2, int N, int[][] weights, int[] values) { 10 | int [][]dp = new int[W1 + 1][W2 + 1]; 11 | for (int i = 1; i <= N; i++) { 12 | int w1 = weights[i - 1][0],w2 = weights[i - 1][1], v = values[i - 1]; 13 | for (int j = W1; j >= w1;j --) { 14 | for (int k = W2;j >= w2;k -- ) 15 | dp[j][k] = Math.max(dp[j][k], dp[j - w1][k - w2] + v); 16 | } 17 | } 18 | return dp[W1][W2]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DP/背包/字符串/分割整数构成字母字符串.java: -------------------------------------------------------------------------------- 1 | package DP.背包.字符串; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/3. 5 | */ 6 | public class 分割整数构成字母字符串 { 7 | public static void main(String[] args) { 8 | String a = "301"; 9 | System.out.println(numDecodings(a)); 10 | } 11 | 12 | public static int numDecodings(String s) { 13 | if(s == null || s.length() == 0) { 14 | return 0; 15 | } 16 | int n = s.length(); 17 | int[] dp = new int[n+1]; 18 | dp[0] = 1; 19 | dp[1] = s.charAt(0) != '0' ? 1 : 0; 20 | for(int i = 2; i <= n; i++) { 21 | int first = Integer.valueOf(s.substring(i-1, i)); 22 | int second = Integer.valueOf(s.substring(i-2, i)); 23 | if(first >= 1 && first <= 9) { 24 | dp[i] += dp[i-1]; 25 | } 26 | if(second >= 10 && second <= 26) { 27 | dp[i] += dp[i-2]; 28 | } 29 | } 30 | return dp[n]; 31 | } 32 | 33 | 34 | // public static int numDecodings(String s) { 35 | // if (s == null || s.equals(""))return 0; 36 | // if (s.equals("0"))return 0; 37 | // if (s.length() >= 2) { 38 | // String s1 = s.substring(0,2); 39 | // int l = Integer.parseInt(s1.substring(0,1)); 40 | // int r = Integer.parseInt(s1.substring(1,2)); 41 | // if (l == 0)return 0; 42 | // int m = l*10 + r; 43 | // if (r == 0 && s.length() == 2 && l < 3) return 1; 44 | // if (r == 0 && m > 26)return 0; 45 | // if (m > 0 && m <= 26) { 46 | // return 2; 47 | // } 48 | // else return 1; 49 | // } 50 | // //s = 1234 51 | // //dp[1] = 1 dp[2] = 2 dp[3] = 3 dp[4] = 3 52 | // int []dp = new int[s.length() + 1]; 53 | // if (s.charAt(0) == '0') { 54 | // return 0; 55 | // } 56 | // else { 57 | // dp[1] = 1; 58 | // } 59 | // for (int i = 2;i <=s.length();i ++) { 60 | // int a = Integer.parseInt(s.substring(i-2,i-1)); 61 | // int b = Integer.parseInt(s.substring(i - 1,i)); 62 | // if (a == 0 && b == 0)return 0; 63 | // if (b == 0 && i == s.length()) { 64 | // if (a * 10 + b > 26) { 65 | // return 0; 66 | // } 67 | // dp[i] = dp[i - 1] - 1; 68 | // break; 69 | // } 70 | // if (a == 0 || b == 0) { 71 | // dp[i] = dp[i - 1]; 72 | // continue; 73 | // } 74 | // int num = a * 10 + b ; 75 | // if (num > 0 && num <= 26) { 76 | // dp[i] = dp[i - 1] + 1; 77 | // }else { 78 | // dp[i] = dp[i - 1]; 79 | // } 80 | // } 81 | // return dp[s.length()]; 82 | // } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/DP/背包/字符串/字符01构成最多的字符串.java: -------------------------------------------------------------------------------- 1 | package DP.背包.字符串; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/8. 5 | */ 6 | public class 字符01构成最多的字符串 { 7 | public static void main(String[] args) { 8 | String []a = {"10", "0001", "111001", "1", "0"}; 9 | System.out.println(findMaxForm(a, 5, 3)); 10 | } 11 | public static int findMaxForm(String[] strs, int m, int n) { 12 | //代表i个0和j个1能够成最多的字符串个数 13 | //首先写出矩阵 14 | int [][]dp = new int[m + 1][n + 1]; 15 | dp[0][0] = 0; 16 | //然后根据条件写一个商品的for循环 17 | for (String str : strs) { 18 | int needZero = 0; 19 | int needOne = 0; 20 | //再根据条件写费用的循环。 21 | //可能是二维费用,则有两个循环。多重背包也类似 22 | //如果是完全背包,则用顺序,01背包用逆序。 23 | 24 | //该步相当于计算放入第i件物品所需的费用。 25 | //因为是二维的,所以类比到01背包,在背包中就是重量和体积 26 | for (int i = 0;i < str.length();i ++) { 27 | if (str.charAt(i) == '0')needZero ++; 28 | else needOne ++; 29 | } 30 | for (int j = m;j >= needZero;j --) { 31 | for (int k = n;k >= needOne;k --) { 32 | dp[j][k] = Math.max(dp[j - needZero][k - needOne] + 1, dp[j][k]); 33 | } 34 | } 35 | } 36 | return dp[m][n]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/DP/背包/字符串/字符串按单词列表分割.java: -------------------------------------------------------------------------------- 1 | package DP.背包.字符串; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by 周杰伦 on 2018/4/6. 9 | */ 10 | public class 字符串按单词列表分割 { 11 | public static void main(String[] args) { 12 | String s = "leetcode"; 13 | List wordDict = new ArrayList<>(); 14 | wordDict.add("leet"); 15 | wordDict.add("code"); 16 | System.out.println(wordBreak(s,wordDict)); 17 | } 18 | //该题与完全背包还是有差异的。解法比较巧妙,最好记着 19 | public static boolean wordBreak(String s, List wordDict) { 20 | //dp[i] represents if s.substring(0, i) is wordbreakable. 21 | boolean []dp = new boolean[s.length() + 1]; 22 | Arrays.fill(dp, false); 23 | dp[0] = true; 24 | for (int i = 1;i <= s.length();i ++) { 25 | for (int j = 0;j < i;j ++) { 26 | if (dp[j] && wordDict.contains(s.substring(j,i))) { 27 | dp[i] = true; 28 | break; 29 | } 30 | } 31 | } 32 | return dp[s.length()]; 33 | } 34 | //这是一个完全背包问题,和 0-1 背包不同的是,完全背包中物品可以使用多次。 35 | // 在这一题当中,词典中的单词可以被使用多次。 36 | 37 | //0-1 背包和完全背包在实现上的不同之处是,0-1 背包对物品的迭代是在最外层, 38 | // 而完全背包对物品的迭代是在最里层。 39 | public boolean wordBreak2(String s, List wordDict) { 40 | int n = s.length(); 41 | boolean[] dp = new boolean[n + 1]; 42 | dp[0] = true; 43 | for (int i = 1; i <= n; i++) { 44 | for (String word : wordDict) { // 每个单词可以使用多次 45 | int len = word.length(); 46 | if (len <= i && word.equals(s.substring(i - len, i))) { 47 | dp[i] = dp[i] || dp[i - len]; 48 | } 49 | } 50 | } 51 | return dp[n]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/DP/背包/完全背包.java: -------------------------------------------------------------------------------- 1 | package DP.背包; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/6. 7 | */ 8 | public class 完全背包 { 9 | //基本解法 10 | //三重循环,效率低 11 | public int knapsack(int W, int N, int[] weights, int[] values) { 12 | int[][] dp = new int[N + 1][W + 1]; 13 | for (int i = 1; i <= N; i++) { 14 | int w = weights[i - 1], v = values[i - 1]; 15 | for (int j = 1; j <= W; j++) { 16 | for (int k = 0;k <= j/w;k ++) { 17 | if (j >= k * w) { 18 | dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - k * w] + k * v); 19 | } else { 20 | dp[i][j] = dp[i - 1][j]; 21 | } 22 | } 23 | } 24 | } 25 | return dp[N][W]; 26 | } 27 | 28 | //转化为01背包的解法 29 | //即F[i][j]=F[i][j-C[i]]+W[i]。为什么会是F[i][j-C[i]]+W[i]? 30 | // 因为我们前面已经最大限度的放了第i件物品,如果能放就放这最后的一件, 31 | //j的循环要正序,因为完全背包的第i个物品出现会影响前面的值。 32 | //即前面的值需要修改,以便于影响后面的值。 33 | public int knapsack03(int W, int N, int[] weights, int[] values) { 34 | int[][] dp = new int[N + 1][W + 1]; 35 | for (int i = 1; i <= N; i++) { 36 | int w = weights[i - 1], v = values[i - 1]; 37 | for (int j = w; j <= W; j++) { 38 | if (j >= w) { 39 | //注意和01背包的区别,这里是dp[i][j-need[i]]+value[i] 40 | dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - w] + v); 41 | } else { 42 | dp[i][j] = dp[i - 1][j]; 43 | } 44 | } 45 | } 46 | return dp[N][W]; 47 | } 48 | 49 | //优化成一维后解法 不必装满 50 | public int knapsack2(int W, int N, int[] weights, int[] values) { 51 | int[]dp = new int[W + 1]; 52 | for (int i = 1; i <= N; i++) { 53 | int w = weights[i - 1], v = values[i - 1]; 54 | for (int j = w; j <= W; j ++) { 55 | if (j >= w) { 56 | dp[j] = Math.max(dp[j], dp[j - w] + v); 57 | } 58 | } 59 | } 60 | return dp[W]; 61 | } 62 | 63 | //优化成一维后解法 必须装满 64 | public int knapsack3(int W, int N, int[] weights, int[] values) { 65 | int[]dp = new int[W + 1]; 66 | Arrays.fill(dp, Integer.MIN_VALUE); 67 | dp[0] = 0; 68 | for (int i = 1; i <= N; i++) { 69 | int w = weights[i - 1], v = values[i - 1]; 70 | for (int j = w; j <= W; j ++) { 71 | if (dp[j - w] != Integer.MIN_VALUE) { 72 | dp[j] = Math.max(dp[j], dp[j - w] + v); 73 | } 74 | } 75 | } 76 | return dp[W]; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/DP/背包/背包01不用装满.java: -------------------------------------------------------------------------------- 1 | package DP.背包; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/6. 7 | */ 8 | public class 背包01不用装满 { 9 | public static void main(String[] args) { 10 | int N = 3; 11 | int W = 10; 12 | int w[] = {3, 4, 5}; 13 | int v[] = {4, 5, 6}; 14 | System.out.println(knapsack(W,N,w,v)); 15 | System.out.println(knapsack2(W,N,w,v)); 16 | } 17 | public static int knapsack(int W, int N, int[] weights, int[] values) { 18 | 19 | int[][] dp = new int[N + 1][W + 1]; 20 | //不用装满就设为0,需要装满的话,求最大值时设为负无穷,求最小值时设为正无穷。 21 | //物品数为0时,取法初始化为0,代表不能装满,但是可以进行累加。因为不需要装满。 22 | Arrays.fill(dp[0], 0); 23 | for (int i = 1; i <= N; i++) { 24 | int w = weights[i - 1], v = values[i - 1]; 25 | for (int j = 1; j <= W; j++) { 26 | if (j >= w) { 27 | dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - w] + v); 28 | } else { 29 | dp[i][j] = dp[i - 1][j]; 30 | } 31 | } 32 | } 33 | return dp[N][W]; 34 | } 35 | 36 | // 优化一维 只对一维有这个要求 37 | //01背包每个物品只装一次,所以后面的结果不影响前面的结果。j应该逆序来算。 38 | //如果正序来算,后面的循环中可能会修改前面的值,这是不被允许的,因为一个物品只放一次。 39 | //后面的循环是不能改前面的值的。 40 | public static int knapsack2(int W, int N, int[] weights, int[] values) { 41 | int []dp = new int[W + 1]; 42 | for (int i = 1; i <= N; i++) { 43 | int w = weights[i - 1], v = values[i - 1]; 44 | for (int j = W; j >= w; j --) { 45 | dp[j] = Math.max(dp[j], dp[j - w] + v); 46 | } 47 | } 48 | return dp[W]; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/DP/背包/背包01需要装满.java: -------------------------------------------------------------------------------- 1 | package DP.背包; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/7. 7 | */ 8 | public class 背包01需要装满 { 9 | public static void main(String[] args) { 10 | int N = 3; 11 | int W = 10; 12 | int w[] = {3, 4, 5}; 13 | int v[] = {4, 5, 6}; 14 | System.out.println(knapsack(W,N,w,v)); 15 | System.out.println(knapsack2(W,N,w,v)); 16 | } 17 | public static int knapsack(int W, int N, int[] weights, int[] values) { 18 | 19 | int[][] dp = new int[N + 1][W + 1]; 20 | //前0个物品永远无法装满1-W重量的背包。置为负无穷,dp累加时只考虑前面已经装满的清空。 21 | Arrays.fill(dp[0], Integer.MIN_VALUE); 22 | //前0个物品刚好可以装满容量为0的背包,此时价值为0,以此为初始值进行累加。 23 | dp[0][0] = 0; 24 | for (int i = 1; i <= N; i++) { 25 | int w = weights[i - 1], v = values[i - 1]; 26 | for (int j = w; j <= W; j++) { 27 | if (j >= w && dp[i - 1][j - w] != Integer.MIN_VALUE) { 28 | dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - w] + v); 29 | } 30 | } 31 | } 32 | return dp[N][W]; 33 | } 34 | 35 | // 优化一维 36 | public static int knapsack2(int W, int N, int[] weights, int[] values) { 37 | int []dp = new int[W + 1]; 38 | //前0个物品永远无法装满1-W重量的背包。置为负无穷,dp累加时只考虑前面已经装满的情况。 39 | Arrays.fill(dp, Integer.MIN_VALUE); 40 | //前0个物品刚好可以装满容量为0的背包,此时价值为0,以此为初始值进行累加。 41 | dp[0]= 0; 42 | for (int i = 1; i <= N; i++) { 43 | int w = weights[i - 1], v = values[i - 1]; 44 | for (int j = W; j >= w; j --) { 45 | if (dp[j - w] != Integer.MIN_VALUE) { 46 | dp[j] = Math.max(dp[j], dp[j - w] + v); 47 | }} 48 | } 49 | return dp[W]; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/DP/背包/背包扩展/划分数组为和相等的两部分.java: -------------------------------------------------------------------------------- 1 | package DP.背包.背包扩展; 2 | 3 | import java.sql.Array; 4 | import java.util.Arrays; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/6. 8 | */ 9 | public class 划分数组为和相等的两部分 { 10 | public static void main(String[] args) { 11 | int []a = {1, 5, 11, 5}; 12 | System.out.println(canPartition2(a)); 13 | } 14 | //优化版 15 | //本题的背包重量就是和的一半。 16 | //每个数都是一个物品的费用。 17 | //于是得dp[i] = dp[i - num[i]] || dp[i] 18 | //由于本题是判断能否加到一个和,所以只判断true和false 19 | //如果是凑成的数量就是 + 1,如果是价值就是加v[i] 20 | public static boolean canPartition2(int[] nums) { 21 | int sum = 0; 22 | for (int i : nums) { 23 | sum += i; 24 | } 25 | if (sum % 2 != 0)return false; 26 | sum = sum/2; 27 | //代表前i个数选出的和可以累加为j。但是i可以选择拿或不拿。 28 | boolean []dp = new boolean[sum + 1]; 29 | Arrays.fill(dp, false); 30 | dp[0] = true; 31 | 32 | for (int i = 0;i < nums.length;i ++) { 33 | for (int j = sum;j >= nums[i];j --) { 34 | dp[j] = dp[j] || dp[j - nums[i]]; 35 | } 36 | } 37 | return dp[sum]; 38 | } 39 | 40 | 41 | public boolean canPartition(int[] nums) { 42 | int sum = 0; 43 | for (int i : nums) { 44 | sum += i; 45 | } 46 | if (sum % 2 != 0)return false; 47 | sum = sum/2; 48 | //代表前i个数选出的和可以累加为j。但是i可以选择拿或不拿。 49 | boolean [][]dp = new boolean[nums.length + 1][sum + 1]; 50 | for (int j = 0;j < nums.length + 1;j ++) { 51 | Arrays.fill(dp[j], false); 52 | } 53 | dp[0][0] = true; 54 | for (int i = 1;i <= nums.length;i ++) { 55 | for (int j = 1;j <= sum;j ++) { 56 | if (j >= nums[i - 1]) { 57 | dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]]; 58 | }else { 59 | dp[i][j] = dp[i - 1][j]; 60 | } 61 | } 62 | } 63 | return dp[nums.length][sum]; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/DP/背包/背包扩展/找零钱.java: -------------------------------------------------------------------------------- 1 | package DP.背包.背包扩展; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/8. 7 | */ 8 | public class 找零钱 { 9 | public static void main(String[] args) { 10 | int []coins = {1, 2, 5}; 11 | System.out.println(coinChange(coins,11)); 12 | } 13 | //是完全背包问题 14 | //无限的硬币凑成一个数 15 | //要求硬币最少,求的是最小值,于是把不符合要求的位置置为正最大。 16 | //类比于背包求最大价值时把不符合要求的位置设为负最大。就是避免经过这些位置。 17 | public static int coinChange(int[] coins, int amount) { 18 | int[]dp = new int[amount + 1]; 19 | Arrays.fill(dp, Integer.MAX_VALUE); 20 | dp[0] = 0; 21 | for (int i = 1;i <= amount;i ++) { 22 | for (int coin : coins) { 23 | if (i >= coin && dp[i - coin] != Integer.MAX_VALUE) { 24 | dp[i] = Math.min(dp[i - coin] + 1, dp[i]); 25 | } 26 | } 27 | } 28 | return dp[amount] != Integer.MAX_VALUE ? dp[amount] : -1; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/DP/背包/背包扩展/组合总和.java: -------------------------------------------------------------------------------- 1 | package DP.背包.背包扩展; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/8. 7 | */ 8 | public class 组合总和 { 9 | static int count = 0; 10 | public static void main(String[] args) { 11 | int []a = {1,2,3}; 12 | System.out.println(combinationSum(a, 32)); 13 | } 14 | //dfs会超时,当target较大时直接超时 15 | public static int combinationSum4(int[] nums, int target) { 16 | count = 0; 17 | dfs(0, nums, target); 18 | return count; 19 | } 20 | public static void dfs(int sum, int []nums, int target) { 21 | if (sum == target) { 22 | count ++; 23 | return; 24 | } 25 | else if (sum > target)return; 26 | 27 | for (int i = 0;i < nums.length;i ++) { 28 | dfs(sum + nums[i],nums,target); 29 | } 30 | return; 31 | } 32 | 33 | 34 | //dp求解 完全背包 35 | public static int combinationSum(int[] nums, int target) { 36 | int []dp = new int[target + 1]; 37 | //这句不对,虽然是要求装满,但是只有求最大值或最小值的时候才需要设置。 38 | // 求使用物品总数,使用物品组成的不同序列的总数等问题时不用设置。 39 | //具体问题具体分析 40 | // Arrays.fill(dp, Integer.MIN_VALUE); 41 | //此处变通一下,dp[0] = 1,而不是dp[0] = 0,否则所有值都为0了 42 | //至于为什么,暂时不知道 43 | //因为dp[1] = dp[0] + dp[1]当数组里有1时,dp[1] = 1. 44 | //为了满足此要求,dp[0] = 1;同理,当j = num[i]时,至少都有一种解。 45 | dp[0] = 1; 46 | for (int j = 1;j <= target;j ++) { 47 | for (int i = 0; i < nums.length; i++) { 48 | if (j >= nums[i] ) { 49 | dp[j] += dp[j - nums[i]]; 50 | } 51 | } 52 | } 53 | return dp[target]; 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/DP/背包/难啊/只能进行k次的股票交易.java: -------------------------------------------------------------------------------- 1 | package DP.背包.难啊; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/8. 5 | */ 6 | public class 只能进行k次的股票交易 { 7 | } 8 | -------------------------------------------------------------------------------- /src/DP/背包/难啊/只能进行两次的股票交易.java: -------------------------------------------------------------------------------- 1 | package DP.背包.难啊; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/8. 5 | */ 6 | public class 只能进行两次的股票交易 { 7 | } 8 | -------------------------------------------------------------------------------- /src/KeysKeyboard.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 周杰伦 on 2018/3/10.650. 2 Keys Keyboard 3 | DescriptionHintsSubmissionsDiscussSolution 4 | Pick One 5 | Initially on a notepad only one character 'A' is present. You can perform two operations on this notepad for each step: 6 | 7 | Copy All: You can copy all the characters present on the notepad (partial copy is not allowed). 8 | Paste: You can paste the characters which are copied last time. 9 | Given a number n. You have to get exactly n 'A' on the notepad by performing the minimum number of steps permitted. Output the minimum number of steps to get n 'A'. 10 | 11 | Example 1: 12 | Input: 3 13 | Output: 3 14 | Explanation: 15 | Intitally, we have one character 'A'. 16 | In step 1, we use Copy All operation. 17 | In step 2, we use Paste operation to get 'AA'. 18 | In step 3, we use Paste operation to get 'AAA'. 19 | Note: 20 | The n will be in the range [1, 1000]. 21 | */ 22 | public class KeysKeyboard { 23 | public int minSteps(int n) { 24 | if (n == 1) { 25 | return 0; 26 | } 27 | else if(n % 2 == 0) { 28 | return minSteps(n/2) + 2; 29 | } 30 | else if( !isPrime(n)) { 31 | return n; 32 | } 33 | else { 34 | double tmp = Math.sqrt(n); 35 | int min = 1000; 36 | for(int i= 2;i <=tmp; i++) { 37 | if (n % i == 0) { 38 | if(minSteps(n/i) + i < min ) { 39 | min = minSteps(n/i) + i; 40 | } 41 | } 42 | } 43 | return min; 44 | } 45 | } 46 | 47 | boolean isPrime( int num ) 48 | { 49 | double tmp = Math.sqrt(num); 50 | for(int i= 2;i <=tmp; i++) { 51 | if (num % i == 0) { 52 | return true; 53 | } 54 | } 55 | return false ; 56 | } 57 | 58 | public static void main(String[] args) { 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/双指针/两数平方和.java: -------------------------------------------------------------------------------- 1 | package 双指针; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/30. 5 | */ 6 | public class 两数平方和 { 7 | public boolean judgeSquareSum(int c) { 8 | double i = 0,j = Math.floor(Math.pow(c,0.5)); 9 | while (i <= j) { 10 | if (i <= j && Math.pow(i,2) + Math.pow(j,2) == c) return true; 11 | else if (i <= j && Math.pow(i,2) + Math.pow(j,2) > c) { 12 | j --; 13 | } 14 | else if (i <= j && Math.pow(i,2) + Math.pow(j,2) < c) { 15 | i ++; 16 | } 17 | } 18 | return false; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/双指针/单链表判环.java: -------------------------------------------------------------------------------- 1 | package 双指针; 2 | /** 3 | * Definition for singly-linked list. 4 | 5 | * } 6 | */ 7 | /** 8 | * Created by 周杰伦 on 2018/3/30. 9 | */ 10 | 11 | class ListNode { 12 | int val; 13 | ListNode next; 14 | 15 | ListNode(int x) { 16 | val = x; 17 | next = null; 18 | } 19 | } 20 | public class 单链表判环 { 21 | 22 | public class Solution { 23 | public boolean hasCycle(ListNode head) { 24 | if (head == null)return false; 25 | if (head.next == head) return true; 26 | ListNode slow = head; 27 | ListNode fast = head; 28 | while (slow.next != null && fast.next != null && fast.next.next != null) { 29 | slow = slow.next; 30 | fast = fast.next.next; 31 | if (slow == fast)return true; 32 | } 33 | return false; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/双指针/反转字符串中的元音字符.java: -------------------------------------------------------------------------------- 1 | package 双指针; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/30. 5 | */ 6 | public class 反转字符串中的元音字符 { 7 | public static void main(String[] args) { 8 | String s = "hello"; 9 | System.out.println(reverseVowels(s)); 10 | } 11 | public static String reverseVowels(String str) { 12 | int i = 0,j = str.length() - 1; 13 | char[] arr = str.toCharArray(); 14 | while (i < j) { 15 | while (i < j && !vowels(arr[i])) { 16 | i ++; 17 | } 18 | while (i < j && !vowels(arr[j])) { 19 | j --; 20 | } 21 | char temp = arr[i]; 22 | arr[i] = arr[j]; 23 | arr[j] = temp; 24 | i ++; 25 | j --; 26 | } 27 | return String.valueOf(arr); 28 | } 29 | public static boolean vowels(char c) { 30 | if (c == 'i' || c =='o' || c == 'a' || c =='e' || c == 'u')return true; 31 | else if (c == 'I' || c == 'O' || c == 'A' || c == 'E' || c == 'U') return true; 32 | else return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/双指针/回文字符串.java: -------------------------------------------------------------------------------- 1 | package 双指针; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/30. 5 | */ 6 | public class 回文字符串 { 7 | public static void main(String[] args) { 8 | System.out.println(validPalindrome("aba")); 9 | } 10 | public static boolean validPalindrome(String s) { 11 | int i = 0,j = s.length() - 1; 12 | while (i < j) { 13 | if (s.charAt(i) != s.charAt(j)) { 14 | return Palindrome(s,i + 1, j) || Palindrome(s, i, j - 1); 15 | } 16 | i ++; 17 | j --; 18 | } 19 | return true; 20 | } 21 | public static boolean Palindrome(String s, int l, int r) { 22 | int i = l,j = r; 23 | while (i < j) { 24 | if (s.charAt(i) != s.charAt(j)) { 25 | return false; 26 | } 27 | i ++; 28 | j --; 29 | } 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/双指针/归并两个有序数组.java: -------------------------------------------------------------------------------- 1 | package 双指针; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/30. 5 | */ 6 | public class 归并两个有序数组 { 7 | public void merge(int[] nums1, int m, int[] nums2, int n) { 8 | if (nums1.length == 1 && nums2.length == 0) return; 9 | if (nums1.length == 1 && nums2 != null)nums1[0] = nums2[0]; 10 | int i = m - 1,j = n - 1; 11 | int index = nums1.length - 1; 12 | while (i >= 0 && j >= 0) { 13 | if (nums1[i] > nums2[j]) { 14 | nums1[index --] = nums1[i]; 15 | nums1[i] = 0; 16 | i --; 17 | } 18 | else { 19 | nums1[index --] = nums2[j]; 20 | j --; 21 | } 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/双指针/最长子序列加强版.java: -------------------------------------------------------------------------------- 1 | package 双指针; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.*; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/3/30. 8 | */ 9 | public class 最长子序列加强版 { 10 | public static void main(String[] args) { 11 | List d = new ArrayList<>(); 12 | d.add("a"); 13 | d.add("b"); 14 | 15 | Collections.sort(d, new Comparator() { 16 | @Override 17 | public int compare(String o1, String o2) { 18 | if (o2.length() == o1.length()) return o1.compareTo(o2); 19 | return o2.length() - o1.length(); 20 | } 21 | }); 22 | System.out.println(Arrays.toString(d.toArray())); 23 | } 24 | public String findLongestWord(String s, List d) { 25 | if (s == null || s.equals(""))return ""; 26 | if (d == null || d.size() == 0)return ""; 27 | Collections.sort(d, new Comparator() { 28 | @Override 29 | public int compare(String o1, String o2) { 30 | if (o2.length() == o1.length()) return o1.compareTo(o2); 31 | return o2.length() - o1.length(); 32 | } 33 | }); 34 | for (String sub : d) { 35 | int i = 0; 36 | int j = 0; 37 | while (i < s.length() && j < sub.length()) { 38 | if (s.charAt(i) != sub.charAt(j)) { 39 | i ++; 40 | } 41 | else { 42 | i ++; 43 | j ++; 44 | } 45 | if (j == sub.length()) { 46 | return sub; 47 | } 48 | } 49 | } 50 | return ""; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/双指针/查找和为9的数对.java: -------------------------------------------------------------------------------- 1 | package 双指针; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/29. 5 | */ 6 | public class 查找和为9的数对 { 7 | public static void main(String[] args) { 8 | 9 | } 10 | public int[] twoSum(int[] numbers, int target) { 11 | int i = 0,j = numbers.length - 1; 12 | int []index = new int[2]; 13 | while (i < j) { 14 | if (numbers[i] + numbers[j] < target) { 15 | i ++; 16 | } 17 | else if (numbers[i] + numbers[j] > target) { 18 | j --; 19 | } 20 | else { 21 | index[0] = i + 1; 22 | index[1] = j + 1; 23 | break; 24 | } 25 | } 26 | return index; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/排序/出现频率最高的k个数.java: -------------------------------------------------------------------------------- 1 | package 排序; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by 周杰伦 on 2018/7/7. 10 | */ 11 | public class 出现频率最高的k个数 { 12 | public List topKFrequent(int[] nums, int k) { 13 | Map map = new HashMap<>(); 14 | for (int i : nums) { 15 | if (map.containsKey(i)) { 16 | map.put(i, map.get(i) + 1); 17 | }else { 18 | map.put(i, 1); 19 | } 20 | } 21 | ArrayList[] timesMap = new ArrayList[nums.length + 1]; 22 | for (int key : map.keySet()) { 23 | int times = map.get(key); 24 | if (timesMap[times] == null) { 25 | timesMap[times] = new ArrayList<>(); 26 | timesMap[times].add(key); 27 | } 28 | else { 29 | timesMap[times].add(key); 30 | } 31 | } 32 | List top = new ArrayList(); 33 | for (int i = timesMap.length - 1;i > 0 && top.size() < k;i ++) { 34 | if (timesMap[i] != null) { 35 | top.addAll(timesMap[i]); 36 | } 37 | } 38 | return top; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/排序/根据字符出现频率排序.java: -------------------------------------------------------------------------------- 1 | package 排序; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/7/7. 8 | */ 9 | public class 根据字符出现频率排序 { 10 | public static void main(String[] args) { 11 | System.out.println(frequencySort("tree")); 12 | } 13 | public static String frequencySort(String s) { 14 | int []arr = new int[128]; 15 | char []crr = s.toCharArray(); 16 | for (char c : crr) { 17 | arr[c]++; 18 | } 19 | 20 | List[]times = new ArrayList[s.length() + 1]; 21 | for (int i = 0;i < arr.length;i ++) { 22 | if (times[arr[i]] == null) { 23 | times[arr[i]] = new ArrayList<>(); 24 | times[arr[i]].add((char) (i)); 25 | }else { 26 | times[arr[i]].add((char) (i)); 27 | } 28 | } 29 | StringBuilder sb = new StringBuilder(); 30 | for (int i = times.length - 1;i > 0 ;i --) { 31 | if (times[i] != null) { 32 | for (char c : times[i]) { 33 | int time = 0; 34 | while (time < i) { 35 | sb.append(c); 36 | time ++; 37 | } 38 | } 39 | } 40 | } 41 | return sb.toString(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/排序/荷兰国旗.java: -------------------------------------------------------------------------------- 1 | package 排序; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/7/7. 5 | */ 6 | public class 荷兰国旗 { 7 | public void sortColors(int[] nums) { 8 | if (nums.length <= 1)return; 9 | int zero = -1, one = 0,two = nums.length; 10 | while (one < two) { 11 | if (nums[one] == 0) { 12 | swap(nums, ++zero, one++); 13 | }else if (nums[one] == 2) { 14 | swap(nums, --two, one); 15 | }else { 16 | one ++; 17 | } 18 | } 19 | } 20 | public void swap(int []nums, int i, int j) { 21 | int tmp = nums[i]; 22 | nums[i] = nums[j]; 23 | nums[j] = tmp; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/数学/公约公倍/最大公约数和最小公倍数.java: -------------------------------------------------------------------------------- 1 | package 数学.公约公倍; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/11. 5 | * 最大公约数 6 | 7 | int gcd(int a, int b) { 8 | return b == 0 ? a : gcd(b, a% b); 9 | } 10 | 最小公倍数为两数的乘积除以最大公约数。 11 | 12 | int lcm(int a, int b){ 13 | return a * b / gcd(a, b); 14 | } 15 | 对于最大公约数问题,因为需要计算 a % b ,而这个操作是比较耗时的,可以使用 编程之美:2.7 的方法,利用减法和移位操作来替换它。 16 | 17 | 对于 a 和 b 的最大公约数 f(a, b),有: 18 | 19 | 如果 a 和 b 均为偶数,f(a, b) = 2*f(a/2, b/2); 20 | 如果 a 是偶数 b 是奇数,f(a, b) = f(a/2, b); 21 | 如果 b 是偶数 a 是奇数,f(a, b) = f(a, b/2); 22 | 如果 a 和 b 均为奇数,f(a, b) = f(a, a-b); 23 | 乘 2 和除 2 都可以转换为移位操作。 24 | */ 25 | public class 最大公约数和最小公倍数 { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/数学/其他/乘积数组.java: -------------------------------------------------------------------------------- 1 | package 数学.其他; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/12. 7 | */ 8 | public class 乘积数组 { 9 | public static void main(String[] args) { 10 | int []a = {1,2,3,4}; 11 | System.out.println(Arrays.toString(productExceptSelf(a))); 12 | } 13 | 14 | // 不用除法 15 | // public int[] productExceptSelf(int[] nums) { 16 | // int n = nums.length; 17 | // int[] ret = new int[n]; 18 | // ret[0] = 1; 19 | // int left = 1; 20 | // for (int i = 1; i < n; i++) { 21 | // ret[i] = left * nums[i - 1]; 22 | // left *= nums[i - 1]; 23 | // } 24 | // int right = 1; 25 | // for (int i = n - 1; i >= 0; i--) { 26 | // ret[i] *= right; 27 | // right *= nums[i]; 28 | // } 29 | // return ret; 30 | // } 31 | 32 | //用了除法 33 | public static int[] productExceptSelf(int[] nums) { 34 | if (nums.length <= 1)return nums; 35 | int all = 1; 36 | int cnt = 0; 37 | int index = 0; 38 | for (int i = 0; i < nums.length;i ++) { 39 | if (nums[i] != 0) { 40 | all *= nums[i]; 41 | }else { 42 | cnt ++; 43 | if (cnt == 2) { 44 | break; 45 | } 46 | index = i; 47 | } 48 | } 49 | if (cnt == 2) { 50 | Arrays.fill(nums, 0); 51 | return nums; 52 | }else { 53 | if (index != 0) { 54 | Arrays.fill(nums, 0); 55 | nums[index] = all; 56 | return nums; 57 | }else { 58 | for (int i = 0;i < nums.length;i ++) { 59 | nums[i] = all / nums[i]; 60 | } 61 | return nums; 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/数学/其他/判断一个数是否是3的n次方.java: -------------------------------------------------------------------------------- 1 | package 数学.其他; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/12. 5 | */ 6 | public class 判断一个数是否是3的n次方 { 7 | public static void main(String[] args) { 8 | System.out.println(isPowerOfThree(45)); 9 | } 10 | // //1162261467是32位系统中,3的最高次幂19 11 | public static boolean isPowerOfThree(int n) { 12 | return n > 0 && (1162261467 % n == 0); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/数学/其他/平方数.java: -------------------------------------------------------------------------------- 1 | package 数学.其他; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/12. 5 | */ 6 | public class 平方数 { 7 | 8 | // 平方序列:1,4,9,16,.. 间隔:3,5,7,... 9 | // 10 | // 间隔为等差数列,使用这个特性可以得到从 1 开始的平方序列。 11 | // 12 | // public boolean isPerfectSquare(int num) { 13 | // int subNum = 1; 14 | // while (num > 0) { 15 | // num -= subNum; 16 | // subNum += 2; 17 | // } 18 | // return num == 0; 19 | // } 20 | 21 | public boolean isPerfectSquare(int num) { 22 | if (num == 1 || num == 0)return true; 23 | for (int i = 2;i <= num / 2;i ++) { 24 | if (i * i == num) { 25 | return true; 26 | } 27 | } 28 | return false; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/数学/其他/找出数组中的乘积最大的三个数.java: -------------------------------------------------------------------------------- 1 | package 数学.其他; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/12. 7 | */ 8 | public class 找出数组中的乘积最大的三个数 { 9 | public static void main(String[] args) { 10 | int []a = {1,2,3,4}; 11 | System.out.println(maximumProduct(a)); 12 | } 13 | public static int maximumProduct(int[] nums) { 14 | if(nums.length < 3) return 0; 15 | if(nums.length == 3) return nums[0] * nums[1] * nums[2]; 16 | Arrays.sort(nums); 17 | int max = Integer.MIN_VALUE; 18 | if ( nums[0] < 0 && nums[1] < 0) { 19 | max = nums[0] * nums[1] * nums[nums.length - 1]; 20 | } 21 | if (nums[nums.length - 1] * nums[nums.length - 2] * nums[nums.length - 3] > max) { 22 | max = nums[nums.length - 1] * nums[nums.length - 2] * nums[nums.length - 3]; 23 | } 24 | return max; 25 | } 26 | 27 | // public int maximumProduct(int[] nums) { 28 | // int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE, min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE; 29 | // for (int n : nums) { 30 | // if (n > max1) { 31 | // max3 = max2; 32 | // max2 = max1; 33 | // max1 = n; 34 | // } else if (n > max2) { 35 | // max3 = max2; 36 | // max2 = n; 37 | // } else if (n > max3) { 38 | // max3 = n; 39 | // } 40 | // 41 | // if (n < min1) { 42 | // min2 = min1; 43 | // min1 = n; 44 | // } else if (n < min2) { 45 | // min2 = n; 46 | // } 47 | // } 48 | // return Math.max(max1*max2*max3, max1*min1*min2); 49 | // } 50 | } 51 | -------------------------------------------------------------------------------- /src/数学/多数投票问题/数组中出现次数多于二分之一n的的元素.java: -------------------------------------------------------------------------------- 1 | package 数学.多数投票问题; 2 | 3 | import java.util.HashMap; 4 | import java.util.Set; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/12. 8 | */ 9 | public class 数组中出现次数多于二分之一n的的元素 { 10 | public static void main(String[] args) { 11 | int []a = {1,3,2,2,76,2,43,2,56,1,2,2,3,3,3,12,2,2,2,2,2,2,2,}; 12 | System.out.println(majorityElement(a)); 13 | } 14 | public static int majorityElement(int[] nums) { 15 | if (nums.length == 0)return 0; 16 | if (nums.length == 1)return nums[0]; 17 | if (nums.length == 2)return nums[0]; 18 | HashMap map = new HashMap<>(); 19 | int n = nums.length; 20 | for (int i = 0; i < nums.length; i++) { 21 | map.put(nums[i], map.getOrDefault(nums[i], 0) + 1); 22 | } 23 | Set set = map.keySet(); 24 | for (int i : set) { 25 | if (map.get(i) > n/2) { 26 | return i; 27 | } 28 | } 29 | return 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/数学/字符串加法减法/二进制加法.java: -------------------------------------------------------------------------------- 1 | package 数学.字符串加法减法; 2 | 3 | import com.sun.org.apache.xerces.internal.impl.dv.xs.Base64BinaryDV; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/12. 7 | */ 8 | public class 二进制加法 { 9 | public String addBinary(String a, String b) { 10 | int carry = 0; 11 | int i = a.length() - 1; 12 | int j = b.length() - 1; 13 | StringBuilder sb = new StringBuilder(); 14 | while (carry == 1|| i >= 0 || j >= 0) { 15 | if (i >= 0 && a.charAt(i --) == '1')carry ++; 16 | if (j >= 0 && b.charAt(j --) == '1')carry ++; 17 | sb.append(carry % 2); 18 | carry /= 2; 19 | } 20 | return sb.reverse().toString(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/数学/字符串加法减法/字符串加法.java: -------------------------------------------------------------------------------- 1 | package 数学.字符串加法减法; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/12. 5 | */ 6 | public class 字符串加法 { 7 | public static void main(String[] args) { 8 | String a ="123"; 9 | String b = "442"; 10 | System.out.println(addStrings(a, b)); 11 | } 12 | public static String addStrings(String num1, String num2) { 13 | int carry = 0; 14 | int i = num1.length() - 1; 15 | int j = num2.length() - 1; 16 | StringBuilder sb = new StringBuilder(); 17 | while (carry == 1|| i >= 0 || j >= 0) { 18 | int x = i < 0 ? 0 : num1.charAt(i --) - '0'; 19 | int y = j < 0 ? 0 : num2.charAt(j --) - '0'; 20 | sb.append((x + y + carry) % 10); 21 | carry = (x + y + carry) / 10; 22 | } 23 | return sb.reverse().toString(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/数学/相遇问题/改变数组元素使所有的数组元素都相等.java: -------------------------------------------------------------------------------- 1 | package 数学.相遇问题; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/12.每次可以对一个数组元素加一或者减一,求最小的改变次数。 7 | 8 | 这是个典型的相遇问题,移动距离最小的方式是所有元素都移动到中位数。理由如下: 9 | 10 | 设 m 为中位数。a 和 b 是 m 两边的两个元素,且 b > a。要使 a 和 b 相等,它们总共移动的次数为 b - a,这个值等于 (b - m) + (m - a),也就是把这两个数移动到中位数的移动次数。 11 | 12 | 设数组长度为 N,则可以找到 N/2 对 a 和 b 的组合,使它们都移动到 m 的位置。 13 | */ 14 | public class 改变数组元素使所有的数组元素都相等 { 15 | public static void main(String[] args) { 16 | int []a = {1,2,3}; 17 | System.out.println(minMoves2(a)); 18 | } 19 | // 20 | public static int minMoves2(int[] nums) { 21 | if (nums.length == 0)return 0; 22 | long []cost = new long[nums.length]; 23 | long min = Integer.MAX_VALUE; 24 | for (int i = 0; i < nums.length; i++) { 25 | for (int j = 0; j < nums.length; j++) { 26 | if (i != j) { 27 | cost[i] += Math.abs(nums[j] - nums[i]); 28 | } 29 | } 30 | if (cost[i] < min) { 31 | min = cost[i]; 32 | } 33 | } 34 | return (int) min; 35 | } 36 | //先排序,时间复杂度:O(NlogN) 37 | // public int minMoves2(int[] nums) { 38 | // Arrays.sort(nums); 39 | // int ret = 0; 40 | // int l = 0, h = nums.length - 1; 41 | // while(l <= h) { 42 | // ret += nums[h] - nums[l]; 43 | // l++; 44 | // h--; 45 | // } 46 | // return ret; 47 | // } 48 | 49 | // 解法 2 50 | 51 | // 使用快速选择找到中位数,时间复杂度 O(N) 52 | // 53 | // public int minMoves2(int[] nums) { 54 | // int ret = 0; 55 | // int n = nums.length; 56 | // int median = quickSelect(nums, 0, n - 1, n / 2 + 1); 57 | // for(int num : nums) ret += Math.abs(num - median); 58 | // return ret; 59 | // } 60 | // 61 | // private int quickSelect(int[] nums, int start, int end, int k) { 62 | // int l = start, r = end, privot = nums[(l + r) / 2]; 63 | // while(l <= r) { 64 | // while(nums[l] < privot) l++; 65 | // while(nums[r] > privot) r--; 66 | // if(l >= r) break; 67 | // swap(nums, l, r); 68 | // l++; r--; 69 | // } 70 | // int left = l - start + 1; 71 | // if(left > k) return quickSelect(nums, start, l - 1, k); 72 | // if(left == k && l == r) return nums[l]; 73 | // int right = r - start + 1; 74 | // return quickSelect(nums, r + 1, end, k - right); 75 | // } 76 | // 77 | // private void swap(int[] nums, int i, int j) { 78 | // int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; 79 | // } 80 | } 81 | -------------------------------------------------------------------------------- /src/数学/素数/生成素数序列.java: -------------------------------------------------------------------------------- 1 | package 数学.素数; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/5. 7 | * 素数 8 | 9 | 素数分解 10 | 11 | 每一个数都可以分解成素数的乘积,例如 84 = 22 * 31 * 50 * 71 * 110 * 130 * 170 * … 12 | 13 | 整除 14 | 15 | 令 x = 2m0 * 3m1 * 5m2 * 7m3 * 11m4 * … 令 y = 2n0 * 3n1 * 5n2 * 7n3 * 11n4 * … 16 | 17 | 如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= ni。 18 | 19 | x 和 y 的 最大公约数 为:gcd(x,y) = 2min(m0,n0) * 3min(m1,n1) * 5min(m2,n2) * ... 20 | 21 | x 和 y 的 最小公倍数 为:lcm(x,y) = 2max(m0,n0) * 3max(m1,n1) * 5max(m2,n2) * ... 22 | */ 23 | public class 生成素数序列 { 24 | public static void main(String[] args) { 25 | 26 | System.out.println(countPrimes(10)); 27 | } 28 | public static int countPrimes(int n) { 29 | boolean []prime = new boolean[n]; 30 | Arrays.fill(prime, true); 31 | int count = 0; 32 | for (int i = 2;i < n;i ++) { 33 | if (prime[i] == true) { 34 | count ++; 35 | } 36 | for (int j = 2;i * j < n;j ++) { 37 | prime[i * j] = false; 38 | } 39 | } 40 | return count; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/数学/进制转换/七进制.java: -------------------------------------------------------------------------------- 1 | package 数学.进制转换; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/11. 7 | */ 8 | public class 七进制 { 9 | //用栈进行进制转换 10 | public static void main(String[] args) { 11 | System.out.println(convertToBase7(-8)); 12 | System.out.println(convertToBase7(-7)); 13 | } 14 | public static String convertToBase7(int num) { 15 | if (num == 0)return "0"; 16 | int flag = 1; 17 | Stack stack = new Stack<>(); 18 | if (num < 0) { 19 | flag = -1; 20 | num = - num; 21 | } 22 | while (num != 0) { 23 | int rem = num % 7; 24 | num = num / 7; 25 | stack.push(rem); 26 | } 27 | String res = ""; 28 | 29 | while (!stack.isEmpty()) { 30 | int last = stack.pop(); 31 | res = res + String.valueOf(last); 32 | } 33 | if (flag == - 1) { 34 | res = "-" + res; 35 | } 36 | return res; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/数学/进制转换/十转十六进制.java: -------------------------------------------------------------------------------- 1 | package 数学.进制转换; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/11. 5 | */ 6 | public class 十转十六进制 { 7 | public static void main(String[] args) { 8 | System.out.println(toHex(26)); 9 | System.out.println(toHex(-1)); 10 | System.out.println(toHexOK(26)); 11 | System.out.println(toHexOK(-1)); 12 | } 13 | //无符号右移高位补0 >>> 14 | //有符号右移高位补1 >>> 15 | public static String toHexOK(int num) { 16 | char[] map = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; 17 | if(num == 0) return "0"; 18 | StringBuilder sb = new StringBuilder(); 19 | while (num != 0) { 20 | sb.append(map[num & 0b1111]); 21 | num >>>= 4; 22 | } 23 | return sb.reverse().toString(); 24 | } 25 | public static String toHex(int num) { 26 | return Integer.toHexString(num); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/数学/阶乘/统计阶乘尾部有多少个0.java: -------------------------------------------------------------------------------- 1 | package 数学.阶乘; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/12. 5 | */ 6 | public class 统计阶乘尾部有多少个0 { 7 | public static void main(String[] args) { 8 | System.out.println(trailingZeroes(5)); 9 | System.out.println(trailingZeroes(7)); 10 | System.out.println(trailingZeroes(13)); 11 | } 12 | //暴力解法不可取 13 | //尾部的 0 由 2 * 5 得来,2 的数量明显多于 5 的数量,因此只要统计有多少个 5 即可。 14 | 15 | //对于一个数 N,它所包含 5 的个数为:N/5 + N/52 + N/53 + ..., 16 | // 其中 N/5 表示不大于 N 的数中 5 的倍数贡献一个 5, 17 | // N/5^2 表示不大于 N 的数中 52 的倍数再贡献一个 5 ...。 18 | public static int trailingZeroes(int n) { 19 | return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5); 20 | } 21 | // public static int trailingZeroes(int n) { 22 | // String res = String.valueOf(floor(n)); 23 | // int cnt = 0; 24 | // for (int i = res.length() - 1; i >= 0 ; i --) { 25 | // if(res.charAt(i) == '0') { 26 | // cnt ++; 27 | // } 28 | // else break; 29 | // } 30 | // return cnt; 31 | // } 32 | // public static long floor (int n) { 33 | // if (n == 1 || n == 0)return 1; 34 | // long []dp = new long[n + 1]; 35 | // dp[1] = 1; 36 | // for (int i = 2; i <= n; i++) { 37 | // dp[i] = dp[i - 1] * i; 38 | // } 39 | // return dp[n]; 40 | // } 41 | } 42 | -------------------------------------------------------------------------------- /src/数学/阶乘/统计阶乘的二进制尾部有多少个0.java: -------------------------------------------------------------------------------- 1 | package 数学.阶乘; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/12. 5 | * 如果统计的是 N! 的二进制表示中最低位 1 的位置,只要统计有多少个 2 即可,该题目出自 编程之美:2.2 。 6 | * 和求解有多少个 5 一样,2 的个数为 N/2 + N/22 + N/23 + ... 7 | */ 8 | public class 统计阶乘的二进制尾部有多少个0 { 9 | public static int trailingZeroes(int n) { 10 | return n == 0 ? 0 : n / 2 + trailingZeroes(n / 2); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/数据结构/位运算/一个数是否为4的n次方.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 一个数是否为4的n次方 { 7 | 8 | public boolean isPowerOfFour(int num) { 9 | if (num < 0) return false; 10 | //保证这个数只有1个1并且1后面只有偶数个0,也就是1在奇数位上 11 | if (Integer.bitCount(num) == 1 && Integer.numberOfTrailingZeros(num) % 2 == 0) { 12 | return true; 13 | } 14 | return false; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/数据结构/位运算/一个数是否是2的n次方.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 一个数是否是2的n次方 { 7 | //2的n次方的二进制表示只有1个1 8 | public boolean isPowerOfTwo(int n) { 9 | if (n < 0) return false; 10 | if (Integer.bitCount(n) == 1) { 11 | return true; 12 | }return false; 13 | } 14 | // 利用 1000 & 0111 == 0 这种性质,得到以下解法: 15 | // 16 | // public boolean isPowerOfTwo(int n) { 17 | // return n > 0 && (n & (n - 1)) == 0; 18 | // } 19 | } 20 | -------------------------------------------------------------------------------- /src/数据结构/位运算/不用额外变量交换两个整数.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 不用额外变量交换两个整数 { 7 | public void swap (int a,int b) { 8 | a = a ^ b; 9 | b = b ^ a; 10 | a = a ^ b; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/数据结构/位运算/位运算基础.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 位运算基础 { 7 | // 位运算 8 | // 9 | //1. 基本原理 10 | // 11 | //0s 表示一串 0,1s 表示一串 1。 12 | // 13 | // x ^ 0s = x x & 0s = 0 x | 0s = x 14 | // x ^ 1s = ~x x & 1s = x x | 1s = 1s 15 | // x ^ x = 0 x & x = x x | x = x 16 | // 利用 x ^ 1s = ~x 的特点,可以将位级表示翻转;利用 x ^ x = 0 的特点,可以将三个数中重复的两个数去除,只留下另一个数。 17 | // 利用 x & 0s = 0 和 x & 1s = x 的特点,可以实现掩码操作。一个数 num 与 mask :00111100 进行位与操作,只保留 num 中与 mask 的 1 部分相对应的位。 18 | // 利用 x | 0s = x 和 x | 1s = 1s 的特点,可以实现设值操作。一个数 num 与 mask:00111100 进行位或操作,将 num 中与 mask 的 1 部分相对应的位都设置为 1。 19 | // 位与运算技巧: 20 | // 21 | // n&(n-1) 去除 n 的位级表示中最低的那一位。例如对于二进制表示 10110 100 ,减去 1 得到 10110011,这两个数相与得到 10110000。 22 | // n-n&(~n+1) 去除 n 的位级表示中最高的那一位。 23 | // n&(-n) 得到 n 的位级表示中最低的那一位。-n 得到 n 的反码加 1,对于二进制表示 10110 100 ,-n 得到 01001100,相与得到 00000100 24 | // 移位运算: 25 | // 26 | // >> n 为算术右移,相当于除以 2n; 27 | // >>> n 为无符号右移,左边会补上 0。 28 | // << n 为算术左移,相当于乘以 2n。 29 | 30 | 31 | // 2. mask 计算 32 | // 33 | // 要获取 111111111,将 0 取反即可,~0。 34 | // 35 | // 要得到只有第 i 位为 1 的 mask,将 1 向左移动 i-1 位即可,1<<(i-1) 。例如 1<<4 得到只有第 5 位为 1 的 mask :00010000。 36 | // 37 | // 要得到 1 到 i 位为 1 的 mask,1<<(i+1)-1 即可,例如将 1<<(4+1)-1 = 00010000-1 = 00001111。 38 | // 39 | // 要得到 1 到 i 位为 0 的 mask,只需将 1 到 i 位为 1 的 mask 取反,即 ~(1<<(i+1)-1)。 40 | 41 | // 3. Java 中的位操作 42 | // 43 | // static int Integer.bitCount(); // 统计 1 的数量 44 | // static int Integer.highestOneBit(); // 获得最高位 45 | // static String toBinaryString(int i); // 转换为二进制表示的字符串 46 | } 47 | -------------------------------------------------------------------------------- /src/数据结构/位运算/判断一个数的位级表示是否不会出现连续的0和1.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | import java.lang.reflect.Parameter; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/27. 7 | */ 8 | public class 判断一个数的位级表示是否不会出现连续的0和1{ 9 | public boolean hasAlternatingBits(int n) { 10 | while (n != 0) { 11 | if (((n >> 1) & 1) == (n & 1)) { 12 | return false; 13 | } 14 | n >>= 1; 15 | } 16 | return true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/数据结构/位运算/字符串数组最大乘积.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 字符串数组最大乘积 { 7 | public int maxProduct(String[] words) { 8 | int n = words.length; 9 | int[] val = new int[n]; 10 | //用一个二进制数来存储一个数所包含的字母种类。 11 | //32位可以容纳26个字母,用数组保存n个二进制数,两两相与,如果结果为0 12 | //说明这两个数没有重复的字母,可以返回。 13 | for (int i = 0; i < n; i++) { 14 | for (char c : words[i].toCharArray()) { 15 | val[i] |= 1 << (c - 'a'); 16 | } 17 | } 18 | int ret = 0; 19 | for (int i = 0; i < n; i++) { 20 | for (int j = i + 1; j < n; j++) { 21 | if ((val[i] & val[j]) == 0) { 22 | ret = Math.max(ret, words[i].length() * words[j].length()); 23 | } 24 | } 25 | } 26 | return ret; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/数据结构/位运算/找出数组中缺失的那个数.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 找出数组中缺失的那个数 { 7 | //和找唯一数一样的思路,数组中的数全部异或,再和1-n的所有数异或。 8 | //最后的结果就是缺少的那个数 9 | public int missingNumber(int[] nums) { 10 | int n = nums.length; 11 | int res = 0; 12 | for (int i : nums) { 13 | res = res ^ i; 14 | } 15 | for (int i = 0;i <= n;i ++) { 16 | res = res ^ i; 17 | } 18 | return res; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/数据结构/位运算/找到仅有的两个不重复的数.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 找到仅有的两个不重复的数 { 7 | public int[] singleNumber(int[] nums) { 8 | int res = 0; 9 | for (int i : nums) { 10 | res = res ^ i; 11 | } 12 | int []arr = new int[2]; 13 | //取到两个不同数异或结果的最右的1。比如0001000 14 | res = res & (-res); 15 | //两个数在这个位上1个为0一个为1,异或后分别得到两个数 16 | for (int i : nums) { 17 | if ((res & i) == 0) { 18 | arr[0] ^= i; 19 | }else { 20 | arr[1] ^= i; 21 | } 22 | } 23 | return arr; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/数据结构/位运算/数组中唯一一个不重复的元素.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 数组中唯一一个不重复的元素 { 7 | public int singleNumber(int[] nums) { 8 | int res = 0; 9 | //相同的元素异或得0,0和唯一的一个元素异或得到该元素 10 | for (int i : nums) { 11 | res = res ^ i; 12 | } 13 | return res; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/数据结构/位运算/整数加法.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 整数加法 { 7 | public int getSum(int a, int b) { 8 | return b == 0 ? a : getSum((a ^ b), (a & b) << 1); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/数据结构/位运算/求一个数的补码.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 求一个数的补码 { 7 | 8 | 9 | // ///题目描述:不考虑二进制表示中的首 0 部分。 10 | // 11 | // 对于 00000101,要求补码可以将它与 00000111 进行异或操作。那么问题就转换为求掩码 00000111。 12 | // 13 | // public int findComplement(int num) { 14 | // if (num == 0) return 1; 15 | // int mask = 1 << 30; 16 | // while ((num & mask) == 0) mask >>= 1; 17 | // mask = (mask << 1) - 1; 18 | // return num ^ mask; 19 | // } 20 | // 可以利用 Java 的 Integer.highestOneBit() 方法来获得含有首 1 的数。 21 | // 22 | // public int findComplement(int num) { 23 | // if (num == 0) return 1; 24 | // int mask = Integer.highestOneBit(num); 25 | // mask = (mask << 1) - 1; 26 | // return num ^ mask; 27 | // } 28 | // 对于 10000000 这样的数要扩展成 11111111,可以利用以下方法: 29 | // 30 | // mask |= mask >> 1 11000000 31 | // mask |= mask >> 2 11110000 32 | // mask |= mask >> 4 11111111 33 | // public int findComplement(int num) { 34 | // int mask = num; 35 | // mask |= mask >> 1; 36 | // mask |= mask >> 2; 37 | // mask |= mask >> 4; 38 | // mask |= mask >> 8; 39 | // mask |= mask >> 16; 40 | // return (mask ^ num); 41 | // } 42 | 43 | public static void main(String[] args) { 44 | findComplement(-1); 45 | } 46 | public static int findComplement(int num) { 47 | if (num >= 0) return num; 48 | int mask = 1; 49 | mask = Integer.MIN_VALUE; 50 | mask -= 1; 51 | System.out.println(Integer.toBinaryString(num)); 52 | num = num ^ mask; 53 | System.out.println(Integer.toBinaryString(mask)); 54 | System.out.println(Integer.toBinaryString(num)); 55 | return 1; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/数据结构/位运算/统计1到n二进制1的个数.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 统计1到n二进制1的个数 { 7 | public int[] countBits(int num) { 8 | int cnt = 0; 9 | int []arr = new int[num + 1]; 10 | for (int i = 1;i <= num;i ++) { 11 | arr[i] = Integer.bitCount(i); 12 | } 13 | return arr; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/数据结构/位运算/统计两个数的二进制表示有多少位不同.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/13. 5 | */ 6 | public class 统计两个数的二进制表示有多少位不同 { 7 | //正确做法,使用异或 8 | public int hammingDistance(int x, int y){ 9 | int z = x ^ y; 10 | //异或的结果中,1所在的位就是x和y不同的位 11 | int cnt = 0; 12 | while (z != 0) { 13 | //最高位是否为1 14 | if ((z & 1) == 1) { 15 | cnt ++; 16 | //依次判断低位是否为1 17 | } 18 | z = z >> 1; 19 | } 20 | return cnt; 21 | } 22 | // 正确方法2 23 | // 使用 z&(z-1) 去除 z 位级表示最低的那一位。 24 | // 25 | // public int hammingDistance(int x, int y) { 26 | // int z = x ^ y; 27 | // int cnt = 0; 28 | // while (z != 0) { 29 | // z &= (z - 1); 30 | // cnt++; 31 | // } 32 | // return cnt; 33 | // } 34 | // 35 | // 方法3 这个方法补错 36 | // 可以使用 Integer.bitcount() 来统计 1 个的个数。 37 | // 38 | // public int hammingDistance(int x, int y) { 39 | // return Integer.bitCount(x ^ y); 40 | 41 | 42 | //错误做法,使用字符串比较 43 | // public static int hammingDistance(int x, int y) { 44 | // String s1 = Integer.toBinaryString(x); 45 | // String s2 = Integer.toBinaryString(y); 46 | // String temp; 47 | // if (s1.length() >= s2.length()) { 48 | // temp = s1; 49 | // s1 = s2; 50 | // s2 = temp; 51 | // } 52 | // System.out.println(s1); 53 | // System.out.println(s2); 54 | // int i = s1.length() - 1; 55 | // int j = s2.length() - 1; 56 | // int cnt = 0; 57 | // while (i >= 0 && j >= 0) { 58 | // if (s1.charAt(i) != s2.charAt(j)) { 59 | // cnt ++; 60 | // i --; 61 | // j --; 62 | // continue; 63 | // } 64 | // i --; 65 | // j --; 66 | // } 67 | // while (j >= 0) { 68 | // if (s2.charAt(j) == '1') { 69 | // cnt ++; 70 | // j --; 71 | // continue; 72 | // } 73 | // j --; 74 | // 75 | // } 76 | // return cnt; 77 | // } 78 | // 79 | // public static void main(String[] args) { 80 | // System.out.println(hammingDistance(3,1)); 81 | // } 82 | } 83 | -------------------------------------------------------------------------------- /src/数据结构/位运算/翻转一个数的比特位.java: -------------------------------------------------------------------------------- 1 | package 数据结构.位运算; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/27. 5 | */ 6 | public class 翻转一个数的比特位 { 7 | // you need treat n as an unsigned value 8 | public int reverseBits(int n) { 9 | int ret = 0; 10 | for (int i = 0; i < 32; i++) { 11 | ret <<= 1; 12 | ret |= (n & 1); 13 | n >>>= 1; 14 | } 15 | return ret; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/数据结构/哈希表/判断数组是否含有相同元素.java: -------------------------------------------------------------------------------- 1 | package 数据结构.哈希表; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/13. 7 | */ 8 | public class 判断数组是否含有相同元素 { 9 | public boolean containsDuplicate(int[] nums) { 10 | HashMap map = new HashMap<>(); 11 | for (int i = 0;i < nums.length;i ++) { 12 | if (map.containsKey(nums[i])) { 13 | return true; 14 | }else { 15 | map.put(nums[i], 1); 16 | } 17 | } 18 | return false; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/数据结构/哈希表/数组中的两个数和为给定值.java: -------------------------------------------------------------------------------- 1 | package 数据结构.哈希表; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/13. 8 | */ 9 | public class 数组中的两个数和为给定值 { 10 | public static void main(String[] args) { 11 | int []a = {3,2,4}; 12 | System.out.println(Arrays.toString(twoSum(a, 6))); 13 | } 14 | public static int[] twoSum(int[] nums, int target) { 15 | int []two = new int[2]; 16 | HashMap map = new HashMap<>(); 17 | for (int i = 0;i < nums.length;i ++) { 18 | map.put(nums[i],i); 19 | } 20 | for (int i = 0;i < nums.length;i ++) { 21 | if (map.containsKey(target - nums[i])) { 22 | if (i == map.get(target - nums[i])) { 23 | continue; 24 | } 25 | two[0] = i; 26 | two[1] = map.get(target - nums[i]); 27 | return two; 28 | } 29 | } 30 | return two; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/数据结构/哈希表/最长和谐序列.java: -------------------------------------------------------------------------------- 1 | package 数据结构.哈希表; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/13. 8 | */ 9 | public class 最长和谐序列 { 10 | public static void main(String[] args) { 11 | int []a = {1,3,2,2,5,2,3,7}; 12 | System.out.println(findLHS(a)); 13 | } 14 | 15 | public static int findLHS(int[] nums) { 16 | int cnt = 1; 17 | HashMap map = new HashMap<>(); 18 | for (int i = 0;i < nums.length;i ++) { 19 | if (map.containsKey(nums[i])) { 20 | cnt ++; 21 | }else { 22 | map.put(nums[i], i); 23 | if (map.containsKey(nums[i] - 1) || map.containsKey(nums[i] + 1)) { 24 | cnt ++; 25 | } 26 | } 27 | } 28 | return cnt; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/数据结构/图/冗余连接.java: -------------------------------------------------------------------------------- 1 | package 数据结构.图; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/13. 5 | */ 6 | public class 冗余连接 { 7 | public int[] findRedundantConnection(int[][] edges) { 8 | int N = edges.length; 9 | UnionFind uf = new UnionFind(N); 10 | for (int[] i : edges) { 11 | int u = i[0]; 12 | int v = i[1]; 13 | if (uf.find(u) == uf.find(v)) { 14 | return i; 15 | } 16 | uf.join(u, v); 17 | } 18 | return new int[]{-1,-1}; 19 | } 20 | class UnionFind { 21 | 22 | UnionFind (int N) { 23 | //一条边就有两个点,所以节点数是边数加一 24 | pre = new int[N + 1]; 25 | for (int i = 0;i < pre.length;i ++) { 26 | pre[i] = i; 27 | } 28 | } 29 | int []pre; 30 | int find(int u) { 31 | return pre[u]; 32 | } 33 | 34 | void join (int u,int v) { 35 | int preU = find(u); 36 | int preV = find(v); 37 | if (preU == preV)return; 38 | //把所有父节点为U的节点指向V节点。因为题目要求把一个图变为一个树 39 | //所以只能有一个根节点,必须把所有二级节点都指向唯一一个节点。 40 | for (int i = 0; i < pre.length; i++) { 41 | if (pre[i] == preU) { 42 | pre[i] = preV; 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/数据结构/图/并查集.java: -------------------------------------------------------------------------------- 1 | package 数据结构.图; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/26. 5 | */ 6 | public class 并查集 { 7 | //并查集用来查找一个节点的父节点是谁。 8 | //如果两个节点的父节点不同并且互相不为父节点,那么他们是不连通的两个点。 9 | //如果两个连通图要合并,只要让一个图的最高级节点指向另一个图的最高级节点 10 | //通过这个方法可以判断使图中节点连捅需要多少的边。 11 | class UnionFind { 12 | 13 | UnionFind (int []edges) { 14 | pre = new int[edges.length]; 15 | for (int i = 0;i < pre.length;i ++) { 16 | pre[i] = i; 17 | } 18 | } 19 | int []pre; 20 | int find(int u) { 21 | return pre[u]; 22 | } 23 | 24 | void join (int u,int v) { 25 | int preU = find(u); 26 | int preV = find(v); 27 | if (preU == preV)return; 28 | pre[preU] = preV; 29 | return; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/数据结构/字符串/两个字符串包含的字符是否完全相同.java: -------------------------------------------------------------------------------- 1 | package 数据结构.字符串; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/13. 5 | */ 6 | public class 两个字符串包含的字符是否完全相同 { 7 | public boolean isAnagram(String s, String t) { 8 | int[] map = new int[26]; 9 | for (int i = 0;i < s.length();i ++) { 10 | map[s.charAt(i) - 'a'] += 1; 11 | } 12 | for (int i = 0;i < t.length();i ++) { 13 | map[s.charAt(i) - 'a'] -= 1; 14 | } 15 | for (int i : map) { 16 | if (i != 0)return false; 17 | } 18 | return true; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/分隔数组.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/18. 5 | */ 6 | public class 分隔数组 { 7 | // 先拆分成若干个数组,每个数组排序 8 | // 如果结果拼起来与原数组的排序相同,则符合。找出可以分隔的最大份数。 9 | 10 | //倒序的放在一起,顺序的拆开,遇到逆序不加,遇到顺序加加。 11 | //注意遇到顺序时,需要与之前的最大值比较。比如18234这种情况,实际上只能分为2个部分。 12 | public static void main(String[] args) { 13 | int []a = {2,0,1}; 14 | int []b = {4,3,2,1,0}; 15 | int []c = {1,0,2,3,4}; 16 | int []d = {1,2,0,3}; 17 | System.out.println(maxChunksToSorted(a)); 18 | System.out.println(maxChunksToSorted(b)); 19 | System.out.println(maxChunksToSorted(c)); 20 | System.out.println(maxChunksToSorted(d)); 21 | } 22 | // 不会,待解 23 | public static int maxChunksToSorted(int[] arr) { 24 | if (arr == null) return 0; 25 | int ret = 0; 26 | int right = arr[0]; 27 | for (int i = 0; i < arr.length; i++) { 28 | right = Math.max(right, arr[i]); 29 | if (right == i) ret++; 30 | } 31 | return ret; 32 | } 33 | // public static int maxChunksToSorted(int[] arr) { 34 | // int cnt = 1; 35 | // int max = arr[0]; 36 | // for (int i = 1;i < arr.length;i ++) { 37 | // if (arr[i] > arr[i - 1] && arr[i] > max ) { 38 | // cnt ++; 39 | // } 40 | // max = Math.max(max, arr[i]); 41 | // } 42 | // return cnt; 43 | // } 44 | } 45 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/寻找所有丢失的元素.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by 周杰伦 on 2018/4/18. 10 | */ 11 | public class 寻找所有丢失的元素 { 12 | public static void main(String[] args) { 13 | int []a = {4,3,2,7,8,2,3,1}; 14 | System.out.println(findDisappearedNumbers(a)); 15 | } 16 | public static List findDisappearedNumbers(int[] nums) { 17 | int []arr = new int[nums.length + 1]; 18 | ArrayList list = new ArrayList<>(); 19 | for (int i = 0;i < nums.length;i ++) { 20 | arr[nums[i]] = 1; 21 | } 22 | for (int i = 1;i < arr.length;i ++) { 23 | if (arr[i] != 1) { 24 | list.add(i); 25 | } 26 | } 27 | return list; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/寻找所有重复的元素.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | import java.sql.Array; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by 周杰伦 on 2018/4/18. 9 | */ 10 | public class 寻找所有重复的元素 { 11 | public static void main(String[] args) { 12 | int []a = {4,3,2,7,8,2,3,1}; 13 | System.out.println(findDuplicates(a)); 14 | } 15 | public static List findDuplicates(int[] nums) { 16 | ArrayList list = new ArrayList<>(); 17 | int []arr = new int[nums.length + 1]; 18 | for (int i = 0;i < nums.length;i ++) { 19 | if (arr[nums[i]] == 0) { 20 | arr[nums[i]] = 1; 21 | }else { 22 | arr[nums[i]] = 2; 23 | } 24 | } 25 | for (int i = 1;i < arr.length;i ++) { 26 | if (arr[i] == 2) { 27 | list.add(i); 28 | } 29 | } 30 | return list; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/嵌套数组.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/18. 8 | */ 9 | public class 嵌套数组 { 10 | public static void main(String[] args) { 11 | int []a = {5,4,0,3,1,6,2}; 12 | System.out.println(arrayNesting(a)); 13 | } 14 | // 访问矩阵的设置用意在于 每次从头开始访问能经历的所有元素都已经标记。 15 | // 后面如果有按照该路径访问的序列,长度都不会比此次序列长。 16 | public static int arrayNesting(int[] nums) { 17 | int cnt = 0; 18 | int max = 0; 19 | for (int j = 0;j < nums.length;j ++ ) { 20 | int index = j; 21 | cnt = 0; 22 | while (index < nums.length && nums[index] != -1) { 23 | cnt ++; 24 | int t = nums[index]; 25 | nums[index] = -1; 26 | index = t; 27 | } 28 | max = Math.max(cnt, max); 29 | } 30 | return max; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/找出丢失的数和重复的数.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.Arrays; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/18. 8 | */ 9 | public class 找出丢失的数和重复的数 { 10 | public static void main(String[] args) { 11 | int []a = {1,5,3,2,2,7,6,4,8,9}; 12 | //[1,5,3,2,2,7,6,4,8,9] 13 | int []b = {3,2,3,4,6,5}; 14 | //[3,2,3,4,6,5] 15 | //233456 16 | System.out.println(Arrays.toString(findErrorNums(b))); 17 | //1223456789 18 | //233456 19 | //1234556 20 | System.out.println(Arrays.toString(findErrorNums(a))); 21 | } 22 | //先找重复,再找丢失 23 | public static int[] findErrorNums(int[] nums) { 24 | Arrays.sort(nums); 25 | int []arr = new int[2]; 26 | int r = 0; 27 | for (int i = 0;i < nums.length - 1;i ++) { 28 | if (nums[i] == nums[i + 1]) { 29 | arr[0] = nums[i]; 30 | r = i; 31 | break; 32 | } 33 | } 34 | for (int i = 0;i <= r;i ++) { 35 | if (i + 1 != nums[i]) { 36 | arr[1] = i + 1; 37 | break; 38 | } 39 | } 40 | if (arr[1] == 0) { 41 | 42 | for (int i = r + 1; i < nums.length; i++) { 43 | if (i != nums[i]) { 44 | arr[1] = i; 45 | break; 46 | } 47 | } 48 | } 49 | if (arr[1] == 0) { 50 | arr[1] = nums.length; 51 | } 52 | return arr; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/找出数组中最长的连续1.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/17. 5 | */ 6 | public class 找出数组中最长的连续1 { 7 | // on 8 | public int findMaxConsecutiveOnes(int[] nums) { 9 | int max = 0; 10 | int count = 0; 11 | for (int i = 0;i < nums.length;i ++) { 12 | if (nums[i] == 1) { 13 | count ++; 14 | if (count > max) { 15 | max = count; 16 | } 17 | }else { 18 | count = 0; 19 | } 20 | } 21 | return max; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/找出数组中重复的数有条件限制.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/18. 7 | */ 8 | public class 找出数组中重复的数有条件限制 { 9 | public int findDuplicate(int[] nums) { 10 | ArrayList list = new ArrayList<>(); 11 | int []arr = new int[nums.length + 1]; 12 | for (int i = 0;i < nums.length;i ++) { 13 | if (arr[nums[i]] == 0) { 14 | arr[nums[i]] = 1; 15 | }else { 16 | arr[nums[i]] ++; 17 | } 18 | } 19 | for (int i = 1;i < arr.length;i ++) { 20 | if (arr[i] > 1) { 21 | return i; 22 | } 23 | } 24 | return 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/把数组中的0移到末尾.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/13. 7 | */ 8 | public class 把数组中的0移到末尾 { 9 | public static void main(String[] args) { 10 | int []a = {0, 1, 0, 3, 12}; 11 | moveZeroes(a); 12 | System.out.println(Arrays.toString(a)); 13 | } 14 | public static void moveZeroes(int[] nums){ 15 | int index = 0; 16 | for (int i = 0;i < nums.length;i ++) { 17 | if (nums[i] != 0) { 18 | nums[index] = nums[i]; 19 | index ++; 20 | } 21 | } 22 | Arrays.fill(nums,index, nums.length, 0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/数组的度.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | import java.util.HashMap; 4 | import java.util.Set; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/17. 8 | */ 9 | public class 数组的度 { 10 | public static void main(String[] args) { 11 | int []a = {1,2,2,3,1,4,2}; 12 | System.out.println(findShortestSubArray(a)); 13 | } 14 | //暴力解法: 15 | //先找到出现次数最多的数。 16 | //可能有多个,对每个数求需要序列的长度。取最小值 17 | public static int findShortestSubArray(int[] nums) { 18 | int max = 0; 19 | int cnt = 0; 20 | HashMap map = new HashMap<>(); 21 | for (int i = 0;i < nums.length;i ++) { 22 | if (map.containsKey(nums[i])) { 23 | map.put(nums[i], map.get(nums[i]) + 1); 24 | }else { 25 | map.put(nums[i], 1); 26 | } 27 | } 28 | Set set = map.keySet(); 29 | for (int i : set) { 30 | max = Math.max(map.get(i), max); 31 | } 32 | System.out.println("max:" + max); 33 | int min = Integer.MAX_VALUE; 34 | for (int x : set) { 35 | cnt = 0; 36 | int k = -1; 37 | for (int i = 0; i < nums.length; i++) { 38 | if (x == nums[i]) { 39 | cnt ++; 40 | if (k == -1) { 41 | k = i; 42 | } 43 | } 44 | if (cnt == max) { 45 | min = Math.min(i - k + 1, min); 46 | break; 47 | } 48 | } 49 | } 50 | return min; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/数组相邻差值的个数.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/17. 7 | */ 8 | public class 数组相邻差值的个数 { 9 | //这题不会 注意一下 10 | //让前 k+1 个元素构建出 k 个不相同的差值,序列为:1 k+1 2 k 3 k-1 ... k/2 k/2+1. 11 | public int[] constructArray(int n, int k) { 12 | int[] ret = new int[n]; 13 | ret[0] = 1; 14 | for (int i = 1, interval = k; i <= k; i++, interval--) { 15 | ret[i] = i % 2 == 1 ? ret[i - 1] + interval : ret[i - 1] - interval; 16 | } 17 | for (int i = k + 1; i < n; i++) { 18 | ret[i] = i + 1; 19 | } 20 | return ret; 21 | } 22 | // public int[] constructArray(int n, int k) { 23 | // int []num = new int[n]; 24 | // int []diff = new int[n]; 25 | // Arrays.fill(diff, -1); 26 | // int x = 1; 27 | // for (int j = 1;j <= n;j ++) { 28 | // num[0] = j; 29 | // int cntk = 0; 30 | // for (int i = 2; i <= n; i++) { 31 | // if (diff[Math.abs(num[x] - num[x - 1])] == -1 && j != i && cntk < k) { 32 | // num[x ++] = i; 33 | // diff[Math.abs(num[x] - num[x - 1])] = 1; 34 | // } 35 | // if (k == cntk) { 36 | // num[x ++] = i; 37 | // if (x == n) { 38 | // return num; 39 | // } 40 | // } 41 | // } 42 | // } 43 | // return num; 44 | // } 45 | } 46 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/矩阵/对角元素相等的矩阵.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵.矩阵; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/17. 5 | */ 6 | public class 对角元素相等的矩阵 { 7 | public static void main(String[] args) { 8 | int [][] matrix = {{1,2,3,4},{5,1,2,3},{9,5,1,2}}; 9 | System.out.println(isToeplitzMatrix(matrix)); 10 | } 11 | //按照每个斜行来判断,一旦有不同的值直接返回false 12 | public static boolean isToeplitzMatrix(int[][] matrix) { 13 | int m = matrix.length; 14 | int n = matrix[0].length; 15 | int len = m > n ? n : m; 16 | for (int i = 1;i < len;i ++) { 17 | if (matrix[i - 1][i - 1] != matrix[i][i]) { 18 | return false; 19 | } 20 | } 21 | for (int i = 1;i < m - 1;i ++) { 22 | for (int j = 0;j < n - 1;j ++) { 23 | if (matrix[i][j] != matrix[i + 1][j + 1]) { 24 | return false; 25 | } 26 | } 27 | } 28 | for (int i = 1;i < n - 1;i ++) { 29 | for (int j = 0;j < m - 1;j ++) { 30 | if (matrix[j][i] != matrix[j + 1][i + 1]) { 31 | return false; 32 | } 33 | } 34 | } 35 | return true; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/矩阵/有序矩阵查找.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵.矩阵; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/18. 5 | */ 6 | public class 有序矩阵查找 { 7 | public static void main(String[] args) { 8 | int [][]a = { 9 | {1, 4, 7, 11, 15}, 10 | {2, 5, 8, 12, 19}, 11 | {3, 6, 9, 16, 22}, 12 | {10, 13, 14, 17, 24}, 13 | {18, 21, 23, 26, 30} 14 | }; 15 | System.out.println(searchMatrix(a,5)); 16 | System.out.println(searchMatrix(a,20)); 17 | 18 | } 19 | public static boolean searchMatrix(int[][] matrix, int target) { 20 | if (matrix.length == 0)return false; 21 | for (int i = matrix[0].length - 1,j = 0;i >= 0 && j < matrix.length;) { 22 | if (target < matrix[j][i]) { 23 | i --; 24 | }else if (target > matrix[j][i]) { 25 | j ++; 26 | }else { 27 | return true; 28 | } 29 | } 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/矩阵/有序矩阵查找第n小的数可重复.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵.矩阵; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/18. 7 | */ 8 | public class 有序矩阵查找第n小的数可重复 { 9 | public int kthSmallest(int[][] matrix, int k) { 10 | int m = matrix.length; 11 | int n = matrix[0].length; 12 | int []arr = new int[m * n]; 13 | int w = 0; 14 | for (int i = 0;i < m;i ++) { 15 | for (int j = 0;j < n;j ++) { 16 | arr[w ++] = matrix[i][j]; 17 | } 18 | } 19 | Arrays.sort(arr); 20 | return arr[k - 1]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/数据结构/数组与矩阵/矩阵/调整矩阵.java: -------------------------------------------------------------------------------- 1 | package 数据结构.数组与矩阵.矩阵; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/17. 5 | */ 6 | public class 调整矩阵 { 7 | //先转存到一维数组,再重新放到新数组。 8 | //如果行列乘积不相等,直接返回原数组。 9 | public int[][] matrixReshape(int[][] nums, int r, int c) { 10 | int m = nums.length,n = nums[0].length; 11 | int [][] arr = new int[r][c]; 12 | int []num = new int[m * n]; 13 | if (m * n == r * c) { 14 | int k = 0; 15 | for (int i = 0 ;i < m;i ++) { 16 | for (int j = 0;j < n;j ++) { 17 | num[k ++] = nums[i][j]; 18 | } 19 | } 20 | k = 0; 21 | for (int i = 0;i < r;i ++) { 22 | for (int j = 0;j < c;j ++) { 23 | arr[i][j] = num[k ++]; 24 | } 25 | } 26 | return arr; 27 | } 28 | return nums; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/数据结构/栈和队列/在另一个数组中比当前元素大的下一个元素.java: -------------------------------------------------------------------------------- 1 | package 数据结构.栈和队列; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/13. 7 | */ 8 | public class 在另一个数组中比当前元素大的下一个元素 { 9 | //这题的测试用例有点问题 10 | public int[] nextGreaterElement(int[] nums1, int[] nums2) { 11 | int []big = new int[nums1.length]; 12 | Arrays.fill(big, -1); 13 | for (int i = 0;i < nums1.length;i ++) { 14 | for (int j = i + 1;j < nums2.length;j ++) { 15 | if (nums2[j] > nums1[i]) { 16 | big[i] = nums2[j]; 17 | break; 18 | } 19 | } 20 | } 21 | return big; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/数据结构/栈和队列/循环数组中比当前元素大的下一个元素.java: -------------------------------------------------------------------------------- 1 | package 数据结构.栈和队列; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/13. 7 | */ 8 | public class 循环数组中比当前元素大的下一个元素 { 9 | //旋转数组很好的解决方式就是复制一份接在后面 10 | public int[] nextGreaterElements(int[] nums) { 11 | int []big = new int[nums.length]; 12 | int []newnum = new int[nums.length * 2]; 13 | Arrays.fill(big, -1); 14 | for (int i = 0;i < nums.length;i ++) { 15 | newnum[i] = nums[i]; 16 | } 17 | for (int i = nums.length;i < newnum.length;i ++) { 18 | newnum[i] = nums[i - nums.length]; 19 | } 20 | for (int i = 0;i < nums.length;i ++) { 21 | for (int j = i + 1;j < newnum.length;j ++) { 22 | if (newnum[j] > nums[i]) { 23 | big[i] = newnum[j]; 24 | break; 25 | } 26 | } 27 | } 28 | return big; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/数据结构/栈和队列/括号匹配.java: -------------------------------------------------------------------------------- 1 | package 数据结构.栈和队列; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/13. 7 | */ 8 | public class 括号匹配 { 9 | public static void main(String[] args) { 10 | 11 | } 12 | public boolean isValid(String s) { 13 | Stack stack = new Stack<>(); 14 | for (int i = 0;i < s.length();i ++) { 15 | char c = s.charAt(i); 16 | switch (c) { 17 | case '(' : stack.push(c); 18 | break; 19 | case '[' : stack.push(c); 20 | break; 21 | case '{' : stack.push(c); 22 | break; 23 | case ')' : { 24 | if (!stack.isEmpty() && stack.peek() == '(') { 25 | stack.pop(); 26 | break; 27 | }else return false; 28 | } 29 | case ']' : { 30 | if (!stack.isEmpty() && stack.peek() == '[') { 31 | stack.pop(); 32 | break; 33 | }else return false; 34 | } 35 | case '}' : { 36 | if (!stack.isEmpty() && stack.peek() == '{') { 37 | stack.pop(); 38 | }else return false; 39 | } 40 | } 41 | } 42 | if (stack.isEmpty()) { 43 | return true; 44 | }else return false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/数据结构/栈和队列/数组中元素与下一个比它大的元素之间的距离.java: -------------------------------------------------------------------------------- 1 | package 数据结构.栈和队列; 2 | 3 | import java.util.Arrays; 4 | import java.util.Stack; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/13. 8 | */ 9 | public class 数组中元素与下一个比它大的元素之间的距离 { 10 | public static void main(String[] args) { 11 | int []a = {73,74,75,71,69,72,76,73}; 12 | System.out.println(Arrays.toString(dailyTemperatures(a))); 13 | } 14 | // 不想用栈 15 | public static int[] dailyTemperatures(int[] temperatures) { 16 | int[]big = new int[temperatures.length]; 17 | Arrays.fill(big, 0); 18 | for (int i = 0;i < temperatures.length - 1;i ++) { 19 | for (int j = i + 1;j < temperatures.length;j ++) { 20 | if (temperatures[j] > temperatures[i]) { 21 | big[i] = j - i; 22 | break; 23 | } 24 | } 25 | } 26 | return big; 27 | } 28 | //用栈的解法,没看懂 29 | public int[] dailyTemperatures2(int[] temperatures) { 30 | int n = temperatures.length; 31 | int[] ret = new int[n]; 32 | Stack stack = new Stack<>(); 33 | 34 | //每次压入一个元素,如果后面的元素大于栈顶元素,则找到。出栈。 35 | //如果不满足,则把当前元素也压栈。重复多次后可能有多个元素在栈内。 36 | //当找到一个满足的元素时,继续判断之前栈中的元素是否小于它。 37 | //若满足则一次可以标记多个元素的距离值。这样的话时间复杂度要低很多。 38 | for(int i = 0; i < n; i++) { 39 | while(!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) { 40 | int idx = stack.pop(); 41 | ret[idx] = i - idx; 42 | } 43 | stack.add(i); 44 | } 45 | return ret; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/数据结构/栈和队列/最小值栈.java: -------------------------------------------------------------------------------- 1 | package 数据结构.栈和队列; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/13. 7 | */ 8 | public class 最小值栈 { 9 | //入栈时压入当前最小值。 10 | //出栈时出栈当前最小值。 11 | //注意所有入栈出栈操作数据栈和最小值栈要一致,否则当多个元素相同时会出错。 12 | class MinStack { 13 | 14 | private Stack dataStack; 15 | private Stack minStack; 16 | private int min; 17 | 18 | public MinStack() { 19 | dataStack = new Stack<>(); 20 | minStack = new Stack<>(); 21 | min = Integer.MAX_VALUE; 22 | } 23 | 24 | public void push(int x) { 25 | dataStack.add(x); 26 | min = Math.min(min, x); 27 | minStack.add(min); 28 | } 29 | 30 | public void pop() { 31 | dataStack.pop(); 32 | minStack.pop(); 33 | min = minStack.isEmpty() ? min = Integer.MAX_VALUE : minStack.peek(); 34 | } 35 | 36 | public int top() { 37 | return dataStack.peek(); 38 | } 39 | 40 | public int getMin() { 41 | return min; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/数据结构/栈和队列/用栈实现队列.java: -------------------------------------------------------------------------------- 1 | package 数据结构.栈和队列; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/13. 7 | */ 8 | public class 用栈实现队列 { 9 | //一个栈实现,内部用一个栈进行倒序 10 | class MyQueue1 { 11 | private Stack st = new Stack(); 12 | 13 | public void push(int x) { 14 | Stack temp = new Stack(); 15 | while (!st.isEmpty()) { 16 | temp.push(st.pop()); 17 | } 18 | st.push(x); 19 | while (!temp.isEmpty()) { 20 | st.push(temp.pop()); 21 | } 22 | } 23 | 24 | public int pop() { 25 | return st.pop(); 26 | } 27 | 28 | public int peek() { 29 | return st.peek(); 30 | } 31 | 32 | public boolean empty() { 33 | return st.isEmpty(); 34 | } 35 | } 36 | //两个栈实现 37 | class MyQueue { 38 | private Stack in = new Stack(); 39 | private Stack out = new Stack(); 40 | 41 | public void push(int x) { 42 | in.push(x); 43 | } 44 | 45 | public int pop() { 46 | in2out(); 47 | return out.pop(); 48 | } 49 | 50 | public int peek() { 51 | in2out(); 52 | return out.peek(); 53 | } 54 | 55 | private void in2out() { 56 | if (out.isEmpty()) { 57 | while (!in.isEmpty()) { 58 | out.push(in.pop()); 59 | } 60 | } 61 | } 62 | 63 | public boolean empty() { 64 | return in.isEmpty() && out.isEmpty(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/数据结构/栈和队列/用队列实现栈.java: -------------------------------------------------------------------------------- 1 | package 数据结构.栈和队列; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/4/13. 8 | */ 9 | public class 用队列实现栈 { 10 | //一个队列实现。每次插入时把除了队头之外的元素移到队尾。 11 | class MyStack { 12 | 13 | private Queue queue; 14 | 15 | public MyStack() { 16 | queue = new LinkedList<>(); 17 | } 18 | 19 | public void push(int x) { 20 | queue.add(x); 21 | int cnt = queue.size(); 22 | while (cnt-- > 1) { 23 | queue.add(queue.poll()); 24 | } 25 | } 26 | 27 | public int pop() { 28 | return queue.remove(); 29 | } 30 | 31 | public int top() { 32 | return queue.peek(); 33 | } 34 | 35 | public boolean empty() { 36 | return queue.isEmpty(); 37 | } 38 | } 39 | 40 | //两个队列实现 41 | //插入时直接插入。 42 | //pop时把除了队尾的元素移到队列2 43 | //队列2满时不能插入。 44 | class MyStack2 { 45 | 46 | private Queue queue; 47 | private Queue queue2; 48 | public MyStack2() { 49 | queue = new LinkedList<>(); 50 | queue2 = new LinkedList<>(); 51 | } 52 | 53 | public void push(int x) { 54 | queue.add(x); 55 | } 56 | 57 | public int pop() { 58 | while (queue.size() > 1) { 59 | queue2.add(queue.poll()); 60 | } 61 | Integer res = queue.poll(); 62 | while (!queue2.isEmpty()) { 63 | queue.add(queue2.poll()); 64 | } 65 | return res; 66 | } 67 | 68 | public int top() { 69 | while (queue.size() > 1) { 70 | queue2.add(queue.poll()); 71 | } 72 | Integer res = queue.peek(); 73 | queue2.add(queue.poll()); 74 | while (!queue2.isEmpty()) { 75 | queue.add(queue2.poll()); 76 | } 77 | return res; 78 | } 79 | 80 | public boolean empty() { 81 | return queue.isEmpty(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/数据结构/树/BST/BST中和为给定值的两个节点.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.BST; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by 周杰伦 on 2018/4/25. 10 | */ 11 | public class BST中和为给定值的两个节点 { 12 | public boolean findTarget(TreeNode root, int k) { 13 | if (root == null)return false; 14 | List list = inorder(root, new ArrayList<>()); 15 | int left = 0; 16 | int right = list.size() - 1; 17 | while (left < right) { 18 | if (list.get(left) + list.get(right) > k) { 19 | right --; 20 | }else if(list.get(left) + list.get(right) < k) { 21 | left ++; 22 | }else return true; 23 | } 24 | return false; 25 | } 26 | public List inorder(TreeNode root, List list) { 27 | if (root == null) return list; 28 | inorder(root.left, list); 29 | list.add(root.val); 30 | inorder(root.right, list); 31 | return list; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/数据结构/树/BST/从有序数组中构造二叉查找树.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.BST; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 从有序数组中构造二叉查找树 { 9 | // Leetcode : 108. Convert Sorted Array to Binary Search Tree (Easy) 10 | 11 | //很有难度啊,必须知道二叉查找树可以用二分法来构造子树,每个中点都是一个根节点。 12 | public TreeNode sortedArrayToBST(int[] nums) { 13 | return toBST(nums, 0, nums.length - 1); 14 | } 15 | 16 | //根据节点的位置关系进行递归 17 | private TreeNode toBST(int[] nums, int sIdx, int eIdx){ 18 | if(sIdx > eIdx) return null; 19 | int mIdx = (sIdx + eIdx) / 2; 20 | TreeNode root = new TreeNode(nums[mIdx]); 21 | root.left = toBST(nums, sIdx, mIdx - 1); 22 | root.right = toBST(nums, mIdx + 1, eIdx); 23 | return root; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/数据结构/树/BST/修剪二叉查找树.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.BST; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 修剪二叉查找树 { 9 | // 二叉查找树(BST):根节点大于等于左子树所有节点,小于等于右子树所有节点。 10 | // 11 | // 只保留值在 L ~ R 之间的节点 12 | 13 | //这个解法绝了。 14 | public TreeNode trimBST(TreeNode root, int L, int R) { 15 | if(root == null) return null; 16 | //若根节点比下限小。只保留右边。 17 | //若根节点比上限大,只保留左边。 18 | if(root.val > R) return trimBST(root.left, L, R); 19 | if(root.val < L) return trimBST(root.right, L, R); 20 | //如果根节点在中间,那么左子树也进行以上操作进行保留 21 | root.left = trimBST(root.left, L, R); 22 | root.right = trimBST(root.right, L, R); 23 | // 24 | return root; 25 | } 26 | // public TreeNode trimBST(TreeNode root, int L, int R) { 27 | // if (root == null)return null; 28 | // TreeNode t = new TreeNode(root.val); 29 | // trimBST(root.left,L,R); 30 | // if (root.val < L) { 31 | // root = root.right; 32 | // 33 | // }else if (root.val > R) { 34 | // root = root.left; 35 | // } 36 | // trimBST(root.right,L,R); 37 | // return root; 38 | // } 39 | } 40 | -------------------------------------------------------------------------------- /src/数据结构/树/BST/在BST中查找两个节点之差的最小绝对值.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.BST; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by 周杰伦 on 2018/4/25. 10 | */ 11 | public class 在BST中查找两个节点之差的最小绝对值 { 12 | public int getMinimumDifference(TreeNode root) { 13 | List list = inorder(root, new ArrayList<>()); 14 | int min = Integer.MAX_VALUE; 15 | for (int i = 1;i < list.size();i ++) { 16 | if (Math.abs(list.get(i) - list.get(i - 1)) < min) { 17 | min = Math.abs(list.get(i) - list.get(i - 1)); 18 | } 19 | } 20 | return min; 21 | } 22 | public List inorder(TreeNode root, List list) { 23 | if (root == null) return list; 24 | inorder(root.left, list); 25 | list.add(root.val); 26 | inorder(root.right, list); 27 | return list; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/数据结构/树/BST/寻找BST中出现次数最多的节点.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.BST; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.*; 6 | 7 | /** 8 | * Created by 周杰伦 on 2018/4/25. 9 | */ 10 | public class 寻找BST中出现次数最多的节点 { 11 | public int[] findMode(TreeNode root) { 12 | ArrayList res = new ArrayList<>(); 13 | List list = inorder(root, new ArrayList<>()); 14 | HashMap map = new HashMap<>(); 15 | int max = 0; 16 | for (int i : list) { 17 | if (map.containsKey(i)) { 18 | map.put(i, map.get(i) + 1); 19 | max = Math.max(max,map.get(i)); 20 | }else { 21 | map.put(i,1); 22 | max = Math.max(max,map.get(i)); 23 | } 24 | } 25 | Set set = map.keySet(); 26 | for (int i : set) { 27 | if (map.get(i) == max) { 28 | res.add(i); 29 | } 30 | } 31 | int []arr = new int[res.size()]; 32 | int index = 0; 33 | for (int i : res) { 34 | arr[index ++] = i; 35 | } 36 | return arr; 37 | } 38 | public List inorder(TreeNode root, List list) { 39 | if (root == null) return list; 40 | inorder(root.left, list); 41 | list.add(root.val); 42 | inorder(root.right, list); 43 | return list; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/数据结构/树/BST/寻找BST的第k个元素.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.BST; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by 周杰伦 on 2018/4/25. 10 | */ 11 | public class 寻找BST的第k个元素 { 12 | public int kthSmallest(TreeNode root, int k) { 13 | if (root == null) return 0; 14 | List list = inorder(root, new ArrayList<>()); 15 | return list.get(k - 1); 16 | } 17 | 18 | public List inorder(TreeNode root, List list) { 19 | if (root == null) return list; 20 | inorder(root.left, list); 21 | list.add(root.val); 22 | inorder(root.right, list); 23 | return list; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/数据结构/树/BST/把BST每个节点的值都加上比它大的节点的值.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.BST; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/25. 7 | */ 8 | public class 把BST每个节点的值都加上比它大的节点的值 { 9 | //先遍历右子树,再遍历根节点,再遍历左子树,就是从大到小遍历, 10 | // 每个遍历到的值加上之前的和就是新的值 11 | public TreeNode convertBST(TreeNode root) { 12 | if (root == null) return null; 13 | int sum = 0; 14 | convertBST(root.right); 15 | sum += root.val; 16 | root.val = sum; 17 | convertBST(root.left); 18 | return root; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/数据结构/树/TreeNode.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/19. 5 | */ 6 | public class TreeNode { 7 | public int val; 8 | public TreeNode left; 9 | public TreeNode right; 10 | public TreeNode(int x) { val = x; } 11 | } 12 | -------------------------------------------------------------------------------- /src/数据结构/树/Trie/Trie求前缀和.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.Trie; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/26. 5 | */ 6 | public class Trie求前缀和 { 7 | class MapSum { 8 | 9 | private class Node { 10 | Node[] child = new Node[26]; 11 | int value; 12 | } 13 | 14 | private Node root = new Node(); 15 | 16 | public MapSum() { 17 | 18 | } 19 | //插入到最后设置节点值 20 | public void insert(String key, int val) { 21 | insert(key, root, val); 22 | } 23 | 24 | private void insert(String key, Node node, int val) { 25 | if (node == null) return; 26 | if (key.length() == 0) { 27 | node.value = val; 28 | return; 29 | } 30 | int index = indexForChar(key.charAt(0)); 31 | if (node.child[index] == null) { 32 | node.child[index] = new Node(); 33 | } 34 | insert(key.substring(1), node.child[index], val); 35 | } 36 | 37 | public int sum(String prefix) { 38 | return sum(prefix, root); 39 | } 40 | 41 | private int sum(String prefix, Node node) { 42 | if (node == null) return 0; 43 | if (prefix.length() != 0) { 44 | //先进行前缀匹配,匹配到最后一个节点。 45 | int index = indexForChar(prefix.charAt(0)); 46 | return sum(prefix.substring(1), node.child[index]); 47 | } 48 | //从匹配到的最后一个节点开始,查找所有子节点,加上这些子节点的和。 49 | //并且递归地加上这些子节点往下的节点值。 50 | int sum = node.value; 51 | for (Node child : node.child) { 52 | sum += sum(prefix, child); 53 | } 54 | return sum; 55 | } 56 | 57 | private int indexForChar(char c) { 58 | return c - 'a'; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/数据结构/树/Trie/实现一个Trie树.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.Trie; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/26. 5 | */ 6 | public class 实现一个Trie树 { 7 | class Trie { 8 | Node root = new Node(); 9 | class Node { 10 | Node[] childs = new Node[26]; 11 | boolean isLeaf; 12 | } 13 | /** Initialize your data structure here. */ 14 | public Trie() { 15 | 16 | } 17 | 18 | /** Inserts a word into the trie. */ 19 | public void insert(String word) { 20 | insert(word, root); 21 | } 22 | public void insert(String word, Node node) { 23 | if (word.length() == 0 ) { 24 | node.isLeaf = true; 25 | return; 26 | } 27 | int index = indexForChar(word.charAt(0)); 28 | if (node.childs[index] == null) { 29 | node.childs[index] = new Node(); 30 | } 31 | insert(word.substring(1), node.childs[index]); 32 | } 33 | /** Returns if the word is in the trie. */ 34 | public boolean search(String word) { 35 | return search(word, root); 36 | } 37 | public boolean search(String word,Node node) { 38 | if (node == null) return false; 39 | if (word.length() == 0 ) return node.isLeaf; 40 | int index = indexForChar(word.charAt(0)); 41 | return search(word.substring(1), node.childs[index]); 42 | } 43 | /** Returns if there is any word in the trie that starts with the given prefix. */ 44 | public boolean startsWith(String prefix) { 45 | return startsWith(prefix, root); 46 | } 47 | public boolean startsWith(String prefix, Node node) { 48 | if (node == null) return false; 49 | if (prefix.length() == 0 ) return true; 50 | int index = indexForChar(prefix.charAt(0)); 51 | return startsWith(prefix.substring(1), node.childs[index]); 52 | } 53 | 54 | public int indexForChar(char c) { 55 | return c - 'a'; 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/数据结构/树/层次遍历/一棵树每层节点的平均数.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.层次遍历; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.*; 6 | 7 | /** 8 | * Created by 周杰伦 on 2018/4/24. 9 | */ 10 | public class 一棵树每层节点的平均数 { 11 | 12 | public List averageOfLevels(TreeNode root) { 13 | if (root == null) return null; 14 | Queue queue = new LinkedList<>(); 15 | List list = new ArrayList<>(); 16 | queue.add(root); 17 | //标识上一行的最后一个节点。 18 | TreeNode last = root; 19 | //标识最后遍历到的一个节点。 20 | TreeNode nlast = null; 21 | double temp = 0; 22 | double cnt= 0; 23 | while (!queue.isEmpty()) { 24 | TreeNode t = queue.poll(); 25 | temp += t.val; 26 | cnt ++; 27 | if (t.left != null) { 28 | queue.add(t.left); 29 | nlast = t.left; 30 | } 31 | if (t.right != null) { 32 | queue.add(t.right); 33 | nlast = t.right; 34 | } 35 | 36 | if (t == last) { 37 | last = nlast; 38 | list.add(temp/cnt); 39 | temp = 0; 40 | cnt = 0; 41 | } 42 | } 43 | return list; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/数据结构/树/层次遍历/得到左下角的节点.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.层次遍历; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | import java.util.Queue; 9 | 10 | /** 11 | * Created by 周杰伦 on 2018/4/24. 12 | */ 13 | public class 得到左下角的节点 { 14 | //其实就是层次遍历的最后一个节点。 15 | public int findBottomLeftValue(TreeNode root) { 16 | Queue queue = new LinkedList<>(); 17 | queue.add(root); 18 | while (!queue.isEmpty()){ 19 | root = queue.poll(); 20 | if (root.right != null) queue.add(root.right); 21 | if (root.left != null) queue.add(root.left); 22 | } 23 | return root.val; 24 | } 25 | 26 | //傻逼了,这样做复杂化了。 27 | // public int findBottomLeftValue(TreeNode root) { 28 | // if (root == null) return 0; 29 | // 30 | // Queue queue = new LinkedList<>(); 31 | // int depth = depth(root); 32 | // int line = 1; 33 | // queue.add(root); 34 | // //标识上一行的最后一个节点。 35 | // TreeNode last = root; 36 | // //标识最后遍历到的一个节点。 37 | // TreeNode nlast = null; 38 | // while (!queue.isEmpty()) { 39 | // TreeNode t = queue.poll(); 40 | // if (line == depth) { 41 | // return t.val; 42 | // } 43 | // if (t.left != null) { 44 | // queue.add(t.left); 45 | // nlast = t.left; 46 | // } 47 | // if (t.right != null) { 48 | // queue.add(t.right); 49 | // nlast = t.right; 50 | // } 51 | // 52 | // if (t == last ) { 53 | // last = nlast; 54 | // line ++; 55 | // } 56 | // } 57 | // return root.val; 58 | // } 59 | // 60 | // public int depth (TreeNode root) { 61 | // if (root == null)return 0; 62 | // int left = depth(root.left); 63 | // int right = depth(root.right); 64 | // return (left > right ? left : right) + 1; 65 | // } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/数据结构/树/层次遍历/间隔遍历.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.层次遍历; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.LinkedList; 6 | import java.util.Queue; 7 | 8 | /** 9 | * Created by 周杰伦 on 2018/4/20. 10 | */ 11 | public class 间隔遍历 { 12 | //前三行的抢法,要么抢13要么抢2,抢2的时候可以选择抢24或者抢3。。以此类推。 13 | //得到最大值。这个题要记 14 | public int rob(TreeNode root) { 15 | if (root == null) return 0; 16 | int val1 = root.val; 17 | if (root.left != null) { 18 | val1 += rob(root.left.left) + rob(root.left.right); 19 | } 20 | if (root.right != null) { 21 | val1 += rob(root.right.left) + rob(root.right.right); 22 | } 23 | int val2 = rob(root.left) + rob(root.right); 24 | return Math.max(val1, val2); 25 | } 26 | //思路有问题,告辞 27 | // public int rob(TreeNode root) { 28 | // if (root == null) return 0; 29 | // int depth = depth(root); 30 | // int max = 0; 31 | // if (depth == 2) { 32 | // max = Math.max(recur(root, 1), max); 33 | // max = Math.max(recur(root, 2), max); 34 | // return max; 35 | // } 36 | // int []visit = new int[depth + 1]; 37 | // visit[0] = 1; 38 | // for (int i = 1;i <= depth;i ++) { 39 | // max = dfs(root, i, depth, 0, visit); 40 | // } 41 | // 42 | // } 43 | // public int dfs(TreeNode t,int cur,int depth, int cnt, int []visit) { 44 | // if (t == null)return 0; 45 | // 46 | // cnt += recur(t,cur); 47 | // visit[cur] = 1; 48 | // 49 | // for (int i = 1;i <= depth ;i ++) { 50 | // if (i - 1 == 0 && visit[i] != 1 && visit[i + 1] != 1) { 51 | // cnt = dfs(t, i, depth, cnt, visit); 52 | // } 53 | // if (i + 1 == depth + 1 && visit[i] != 1 && visit[i - 1] != 1) { 54 | // cnt = dfs(t, i, depth, cnt, visit); 55 | // } 56 | // if (visit[i] != 1 && i - 1 >= 1 && visit[i - 1] != 1 && visit[i + 1] != 1) { 57 | // cnt = dfs(t, i, depth, cnt, visit); 58 | // } 59 | // } 60 | // } 61 | // public int depth (TreeNode root) { 62 | // if (root == null)return 0; 63 | // int left = depth(root.left); 64 | // int right = depth(root.right); 65 | // return (left > right ? left : right) + 1; 66 | // } 67 | // public int recur(TreeNode root,int line) { 68 | // if (root == null) return 0; 69 | // Queue queue = new LinkedList<>(); 70 | // queue.add(root); 71 | // int max = 0; 72 | // //标识上一行的最后一个节点。 73 | // TreeNode last = root; 74 | // //标识最后遍历到的一个节点。 75 | // TreeNode nlast = null; 76 | // int cur = 1; 77 | // int temp = 0; 78 | // while (!queue.isEmpty()) { 79 | // TreeNode t = queue.poll(); 80 | // temp += t.val; 81 | // if (t.left != null) { 82 | // queue.add(t.left); 83 | // nlast = t.left; 84 | // } 85 | // if (t.right != null) { 86 | // queue.add(t.right); 87 | // nlast = t.right; 88 | // } 89 | // 90 | // if (t == last) { 91 | // last = nlast; 92 | // if (line == cur) { 93 | // max = Math.max(max, temp); 94 | // } 95 | // temp = 0; 96 | // cur ++; 97 | // } 98 | // } 99 | // return max; 100 | // } 101 | } 102 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/平衡树.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 平衡树 { 9 | public boolean isBalanced(TreeNode root) { 10 | if (root == null)return true; 11 | int left = maxDepth(root.left); 12 | int right = maxDepth(root.right); 13 | if (Math.abs(left - right) > 1)return false; 14 | return isBalanced(root.left) && isBalanced(root.right); 15 | } 16 | public int maxDepth(TreeNode root) { 17 | if (root == null)return 0; 18 | int left = maxDepth(root.left); 19 | int right = maxDepth(root.right); 20 | return (left > right ? left : right) + 1; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/树的操作/子树.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.树的操作; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | * 8 | 3 9 | / \ 10 | 4 5 11 | / \ 12 | 1 2 13 | 14 | 4 15 | / \ 16 | 1 2 17 | */ 18 | public class 子树 { 19 | //判断是非问题时,先把不满足的情况找出来。再把需要满足的情况找出来。最后返回递归 20 | public boolean isSubtree(TreeNode s, TreeNode t) { 21 | if (s == null)return false; 22 | if (recur(s,t))return true; 23 | if (isSubtree(s.left,t)) return true; 24 | if (isSubtree(s.right,t)) return true; 25 | return false; 26 | } 27 | 28 | public boolean recur (TreeNode s, TreeNode t) { 29 | if (s == null && t == null)return true; 30 | if (s == null || t == null)return false; 31 | if (s.val != t.val)return false; 32 | return recur(s.left, t.left) && recur(s.right, t.right); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/树的操作/归并两棵树.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.树的操作; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 归并两棵树 { 9 | public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { 10 | if (t1 == null)return t2; 11 | if (t2 == null)return t1; 12 | TreeNode t = new TreeNode(t1.val); 13 | t.val = t1.val + t2.val; 14 | t.left = mergeTrees(t1.left, t2.left); 15 | t.right = mergeTrees(t1.right, t2.right); 16 | return t; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/树的操作/树的对称.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.树的操作; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 树的对称 { 9 | public boolean isSymmetric(TreeNode root) { 10 | if (root == null)return true; 11 | return recur(root.left, root.right); 12 | } 13 | public boolean recur(TreeNode left, TreeNode right) { 14 | if (left == null && right == null)return true; 15 | if (left == null )return false; 16 | if (right == null )return false; 17 | if (left.val != right.val) return false; 18 | 19 | //该部分代码可以省略,因为这部分的判断是递归中已经包含了的 20 | // if (left.left == null && left.right == null && 21 | // right.left == null && right.right == null )return true; 22 | 23 | return recur(left.left, right.right) && recur(left.right, right.left); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/树的操作/翻转树.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.树的操作; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 翻转树 { 9 | public TreeNode invertTree(TreeNode root) { 10 | if (root == null)return root; 11 | TreeNode temp = root.left; 12 | root.left = root.right; 13 | root.right = temp; 14 | invertTree(root.left); 15 | invertTree(root.right); 16 | return root; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/树的高度.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/13. 7 | */ 8 | public class 树的高度 { 9 | public static void main(String[] args) { 10 | 11 | } 12 | 13 | public int maxDepth(TreeNode root) { 14 | if (root == null)return 0; 15 | int left = maxDepth(root.left); 16 | int right = maxDepth(root.right); 17 | return (left > right ? left : right) + 1; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/节点/二叉查找树的最近公共祖先.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.节点; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 二叉查找树的最近公共祖先 { 9 | //根据查找树的性质,如果节点值在这两个值中间,就是最近公共祖先。 10 | //若比两个节点都大,找左子树,否则找右子树。 11 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 12 | if (root == null)return null; 13 | if (root.val >= p.val && root.val <= q.val || root.val <= p.val && root.val >= q.val ) { 14 | return root; 15 | }else if (root.val > p.val && root.val > q.val){ 16 | return lowestCommonAncestor(root.left, p, q); 17 | }else if (root.val < p.val && root.val < q.val) { 18 | return lowestCommonAncestor(root.right, p, q); 19 | } 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/节点/找出二叉树中第二小的节点.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.节点; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 找出二叉树中第二小的节点 { 9 | public static void main(String[] args) { 10 | } 11 | //先找到最小值,再找第二小值 12 | public int findSecondMinimumValue(TreeNode root) { 13 | if (root == null)return -1; 14 | int first = findMin(root, Integer.MAX_VALUE, -1); 15 | int second = findMin(root, Integer.MAX_VALUE, first); 16 | if (second == Integer.MAX_VALUE)return - 1; 17 | return second; 18 | } 19 | public int findMin (TreeNode root, int min, int f) { 20 | if (root == null)return min; 21 | if (root.val < min && root.val != f)min = root.val; 22 | min = Math.min(findMin(root.left, min, f), min); 23 | min = Math.min(findMin(root.right, min, f), min); 24 | return min; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/节点/统计左叶子节点的和.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.节点; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 统计左叶子节点的和 { 9 | public int sumOfLeftLeaves(TreeNode root) { 10 | if (root == null)return 0; 11 | int sum = 0; 12 | if (root.left != null && root.left.left == null && root.left.right == null) { 13 | sum += root.left.val; 14 | } 15 | sum += sumOfLeftLeaves(root.left); 16 | sum += sumOfLeftLeaves(root.right); 17 | return sum; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/路径/两节点的最长路径.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.路径; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 两节点的最长路径 { 9 | //从任一个节点出发找两边最长的边,相加即为该点为中心的最长路径。 10 | //遍历一遍二叉树找出这些路径中最长的。 11 | public int diameterOfBinaryTree(TreeNode root) { 12 | if (root == null)return 0; 13 | int left = recur(root.left, 0); 14 | int right = recur(root.right, 0); 15 | int max = left + right; 16 | max = Math.max(max, diameterOfBinaryTree(root.left)); 17 | max = Math.max(max, diameterOfBinaryTree(root.right)); 18 | return max; 19 | } 20 | public int recur (TreeNode root, int sum) { 21 | if (root == null)return sum; 22 | if (root.left == null && root.right == null) return sum + 1; 23 | int left = recur(root.left, sum + 1); 24 | int right = recur(root.right, sum + 1); 25 | return Math.max(left, right); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/路径/判断路径和是否等于一个数.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.路径; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 判断路径和是否等于一个数 { 9 | //本题有个坑。空树一定返回false。所以要判断左右子树为空并且val = sum。 10 | //而不能直接判断sum = 0 && root = null 11 | public boolean hasPathSum(TreeNode root, int sum) { 12 | if (root == null) return false; 13 | if (root.left == null && root.right == null && root.val == sum)return true; 14 | sum -= root.val; 15 | boolean left = hasPathSum(root.left, sum); 16 | boolean right = hasPathSum(root.right, sum); 17 | return left || right; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/路径/最小路径.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.路径; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 最小路径 { 9 | //其实找的是根节点到叶子节点的最小路径值 10 | public int minDepth(TreeNode root) { 11 | if (root == null)return 0; 12 | int left = minDepth(root.left); 13 | int right = minDepth(root.right); 14 | //如果左右子树有一个为空,只能取不为空的长度 15 | if (left == 0 || right == 0)return left + right + 1; 16 | //如果都不为空,则取小的那一个。妙啊 17 | return Math.min(left,right) + 1; 18 | 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/路径/相同节点值的最大路径长度.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.路径; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 相同节点值的最大路径长度 { 9 | private int path = 0; 10 | 11 | public int longestUnivaluePath(TreeNode root) { 12 | dfs(root); 13 | return path; 14 | } 15 | 16 | private int dfs(TreeNode root){ 17 | if (root == null) return 0; 18 | int left = dfs(root.left); 19 | int right = dfs(root.right); 20 | int leftPath = root.left != null && root.left.val == root.val ? left + 1 : 0; 21 | int rightPath = root.right != null && root.right.val == root.val ? right + 1 : 0; 22 | path = Math.max(path, leftPath + rightPath); 23 | return Math.max(leftPath, rightPath); 24 | } 25 | //不知道哪里做错了,很烦 26 | // public int longestUnivaluePath(TreeNode root) { 27 | // if (root == null) return 0; 28 | // int max = 0; 29 | // int left = 0,right = 0; 30 | // if (root.left != null && root.val == root.left.val) { 31 | // left ++; 32 | // } 33 | // if (root.right != null && root.val == root.right.val) { 34 | // right ++; 35 | // } 36 | // left = recur(root.left, left); 37 | // right = recur(root.right, right); 38 | // max = left + right; 39 | // max = Math.max(longestUnivaluePath(root.left), max); 40 | // max = Math.max(longestUnivaluePath(root.right), max); 41 | // return max; 42 | // } 43 | // public int recur (TreeNode t,int cnt) { 44 | // if (t == null)return cnt; 45 | // int left = cnt; 46 | // int right = cnt; 47 | // if (t.left != null && t.val == t.left.val) { 48 | // left = recur(t.left, cnt + 1); 49 | // } 50 | // if (t.right != null && t.val == t.right.val) { 51 | // right = recur(t.right, cnt + 1); 52 | // } 53 | // return left > right ? left : right; 54 | // } 55 | } 56 | -------------------------------------------------------------------------------- /src/数据结构/树/递归/路径/统计路径和等于一个数的路径数量.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.递归.路径; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 统计路径和等于一个数的路径数量 { 9 | public static void main(String[] args) { 10 | TreeNode t1 = new TreeNode(1); 11 | TreeNode t2 = new TreeNode(2); 12 | TreeNode t3 = new TreeNode(3); 13 | TreeNode t4 = new TreeNode(5); 14 | t2.right = t3; 15 | t1.left = t2; 16 | t1.right = t4; 17 | System.out.println(pathSum(t1, 6)); 18 | } 19 | //从树中任意一点出发,找到一段路径和为sum即可。 20 | public static int pathSum(TreeNode root, int sum) { 21 | if (root == null)return 0; 22 | int cnt = count(root, sum); 23 | cnt += pathSum(root.left, sum); 24 | cnt += pathSum(root.right, sum); 25 | return cnt; 26 | } 27 | 28 | //从该节点往下寻找,满足条件即可以++ 29 | public static int count(TreeNode root, int sum) { 30 | if (root == null) return 0; 31 | int cnt = 0; 32 | if (root.val == sum) cnt ++; 33 | cnt += count(root.left, sum - root.val); 34 | cnt += count(root.right, sum - root.val); 35 | return cnt; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/数据结构/树/遍历/中序非递归.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.遍历; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Stack; 8 | 9 | /** 10 | * Created by 周杰伦 on 2018/4/25. 11 | */ 12 | public class 中序非递归 { 13 | public List inorderTraversal(TreeNode root) { 14 | if (root == null) return new ArrayList<>(); 15 | Stack stack = new Stack<>(); 16 | List list = new ArrayList<>(); 17 | TreeNode p = root; 18 | stack.push(p); 19 | //p.left代表新进栈的值,stack里的是原来待遍历的值,两边都为空时说明遍历结束。 20 | while (p.left != null || !stack.isEmpty()) { 21 | //先把左子树的节点进栈。 22 | while (p.left != null) { 23 | p = p.left; 24 | stack.push(p); 25 | } 26 | //左下角节点出栈并访问,如果他有右子树,右子树进栈,并且退出循环 27 | //进入第一个环节,将该右子树节点的所有左节点进栈,以此类推即可完成。 28 | while (!stack.isEmpty()) { 29 | TreeNode t = stack.pop(); 30 | list.add(t.val); 31 | if (t.right != null) { 32 | stack.push(t.right); 33 | p = t.right; 34 | break; 35 | } 36 | } 37 | } 38 | return list; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/数据结构/树/遍历/先序非递归.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.遍历; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Stack; 8 | 9 | /** 10 | * Created by 周杰伦 on 2018/4/25. 11 | */ 12 | public class 先序非递归 { 13 | public List preorderTraversal(TreeNode root) { 14 | if (root == null) return new ArrayList<>(); 15 | Stack stack = new Stack<>(); 16 | List list = new ArrayList<>(); 17 | stack.push(root); 18 | while (!stack.isEmpty()) { 19 | TreeNode t = stack.pop(); 20 | list.add(t.val); 21 | if (t.right != null) { 22 | stack.push(t.right); 23 | } 24 | if (t.left != null) { 25 | stack.push(t.left); 26 | } 27 | } 28 | return list; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/数据结构/树/遍历/后序非递归.java: -------------------------------------------------------------------------------- 1 | package 数据结构.树.遍历; 2 | 3 | import 数据结构.树.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Stack; 8 | 9 | /** 10 | * Created by 周杰伦 on 2018/4/25. 11 | */ 12 | public class 后序非递归 { 13 | public List postorderTraversal(TreeNode root) { 14 | if (root == null) return new ArrayList<>(); 15 | Stack stack = new Stack<>(); 16 | List list = new ArrayList<>(); 17 | recur(stack, root); 18 | while (!stack.isEmpty()) { 19 | list.add(stack.pop().val); 20 | } 21 | return list; 22 | } 23 | 24 | public void recur (Stack stack, TreeNode root) { 25 | if (root == null) return; 26 | stack.push(root); 27 | recur(stack, root.right); 28 | recur(stack, root.left); 29 | return; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/数据结构/链表/ListNode.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/19. 5 | */ 6 | public class ListNode { 7 | int val; 8 | ListNode next; 9 | ListNode(int x) { val = x; } 10 | } 11 | -------------------------------------------------------------------------------- /src/数据结构/链表/交换链表中的相邻结点.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/19. 5 | */ 6 | public class 交换链表中的相邻结点 { 7 | public static void main(String[] args) { 8 | ListNode l1 = new ListNode(1); 9 | ListNode l2 = new ListNode(2); 10 | ListNode l3 = new ListNode(3); 11 | ListNode l4 = new ListNode(4); 12 | l3.next = l4; 13 | l2.next = l3; 14 | l1.next = l2; 15 | System.out.println(swapPairs(l1)); 16 | } 17 | public static ListNode swapPairs(ListNode head) { 18 | if (head == null) return null; 19 | if (head.next == null) { 20 | return head; 21 | } 22 | ListNode h = new ListNode(0); 23 | ListNode p = h; 24 | ListNode l = head; 25 | ListNode r = head.next; 26 | while (l != null && r != null) { 27 | ListNode temp = r.next; 28 | r.next = l; 29 | h.next = r; 30 | h = h.next.next; 31 | l = temp; 32 | if (l != null && l.next != null) { 33 | r = l.next; 34 | }else { 35 | h.next = l; 36 | return p.next; 37 | } 38 | } 39 | return p.next; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/数据结构/链表/从有序链表中删除重复节点.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/19. 5 | */ 6 | public class 从有序链表中删除重复节点 { 7 | public ListNode deleteDuplicates(ListNode head) { 8 | if (head == null) return null; 9 | ListNode h = head; 10 | while (h.next != null) { 11 | if (h.val == h.next.val) { 12 | h.next = h.next.next; 13 | }else { 14 | h = h.next; 15 | } 16 | } 17 | return head; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/数据结构/链表/分隔链表.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/20. 5 | */ 6 | public class 分隔链表 { 7 | //多个节点串联的链表如何解决修改问题,修改节点的next会导致丢失后面的节点。 8 | //上面这个问题虽然解决了,但是除法得到余数的分段方式没想出来。 9 | // public ListNode[] splitListToParts(ListNode root, int k) { 10 | // ListNode []arr = new ListNode[k]; 11 | // int size = size(root); 12 | // if (size <= k) { 13 | // int i = 0; 14 | // //每格只装一个,其余用null填补 15 | // ListNode l = root; 16 | // while (l != null) { 17 | // arr[i ++] = new ListNode(l.val); 18 | // l = l.next; 19 | // } 20 | // return arr; 21 | // } 22 | // int len = size/k; 23 | // int rem = size - len * k; 24 | // //这部分操作不知道怎么进行了 25 | // if (rem == 0) { 26 | // //每部分都一样长。 27 | // int i = 0; 28 | // //每格装len个 29 | // ListNode l = root; 30 | // ListNode next = l; 31 | // while (i < k && next != null) { 32 | // ListNode node = next; 33 | // l = node; 34 | // int cnt = 1; 35 | // 36 | // while (cnt < len) { 37 | // l = l.next; 38 | // cnt ++; 39 | // } 40 | // next = l.next; 41 | // l.next = null; 42 | // arr[i ++] = node; 43 | // } 44 | // }else { 45 | // //有一部分多出来长度。 46 | // int i = 0; 47 | // //第一格装len + 1个,其他每格装len个 48 | // ListNode l = root; 49 | // ListNode next = l; 50 | // ListNode node = l; 51 | // int firstlen = 1; 52 | // while (firstlen < len + 1) { 53 | // l = l.next; 54 | // firstlen ++; 55 | // } 56 | // next = l.next; 57 | // l.next = null; 58 | // arr[i ++] = node; 59 | // //除了第一格 60 | // 61 | // while (i < k && next != null) { 62 | // node = next; 63 | // l = node; 64 | // int cnt = 1; 65 | // 66 | // while (cnt < len) { 67 | // l = l.next; 68 | // cnt ++; 69 | // } 70 | // next = l.next; 71 | // l.next = null; 72 | // arr[i ++] = node; 73 | // } 74 | // } 75 | // return arr; 76 | // } 77 | // public int size(ListNode node) { 78 | // int len = 0; 79 | // while (node != null) { 80 | // len ++; 81 | // node = node.next; 82 | // } 83 | // return len; 84 | // } 85 | 86 | // 题目描述:把链表分隔成 k 部分,每部分的长度都应该尽可能相同,排在前面的长度应该大于等于后面的。 87 | 88 | public ListNode[] splitListToParts(ListNode root, int k) { 89 | int N = 0; 90 | ListNode cur = root; 91 | while (cur != null) { 92 | N++; 93 | cur = cur.next; 94 | } 95 | int mod = N % k; 96 | int size = N / k; 97 | ListNode[] ret = new ListNode[k]; 98 | cur = root; 99 | for (int i = 0; cur != null && i < k; i++) { 100 | ret[i] = cur; 101 | int curSize = size + (mod-- > 0 ? 1 : 0); 102 | for (int j = 0; j < curSize - 1; j++) { 103 | cur = cur.next; 104 | } 105 | ListNode next = cur.next; 106 | cur.next = null; 107 | cur = next; 108 | } 109 | return ret; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/数据结构/链表/删除链表的倒数第n个节点.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/19. 5 | */ 6 | public class 删除链表的倒数第n个节点 { 7 | public ListNode removeNthFromEnd(ListNode head, int n) { 8 | if (head == null)return null; 9 | //若要删除倒数第n个刚好与长度相等时。要另外判断,否则会出错。 10 | ListNode p = head; 11 | int len = 0; 12 | while (p != null) { 13 | p = p.next; 14 | len ++; 15 | } 16 | if (n == len) { 17 | head = head.next; 18 | return head; 19 | } 20 | //一般情况下,直接用快慢指针,快指针先走n步。满指针负责删除。 21 | //当满指针前面没元素时,说明只有一个元素,返回空即可。 22 | ListNode slow = head; 23 | ListNode fast = head; 24 | int cnt = 0; 25 | while (fast.next != null && cnt < n) { 26 | fast = fast.next; 27 | cnt ++; 28 | } 29 | while (fast.next != null) { 30 | slow = slow.next; 31 | fast = fast.next; 32 | } 33 | if (slow.next != null) { 34 | slow.next = slow.next.next; 35 | return head; 36 | }else { 37 | return null; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/数据结构/链表/回文链表.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 回文链表 { 9 | 10 | //对回文理解有偏差了。 11 | //以为只有1001 221122这种才是。 12 | //事实上101 10001 这种也是 13 | // public boolean isPalindrome(ListNode head) { 14 | // Stack stack = new Stack<>(); 15 | // ListNode p = head; 16 | // if (head == null)return true; 17 | // if (head.next == null)return true; 18 | // while (p != null) { 19 | // if (p.next != null && (p.val != p.next.val ||p.next.next != null && p.val != p.next.next.val)){ 20 | // stack.push(p); 21 | // p = p.next; 22 | // continue; 23 | // } 24 | // if (p.next == null) { 25 | // return false; 26 | // }else { 27 | // if (p.next.next != null && p.val == p.next.next.val) { 28 | // p = p.next.next; 29 | // }else { 30 | // p = p.next; 31 | // } 32 | // while (!stack.isEmpty() && p.next != null) { 33 | // ListNode top = stack.pop(); 34 | // p = p.next; 35 | // if (top.val != p.val) { 36 | // return false; 37 | // } 38 | // } 39 | // if (stack.isEmpty() && p.next == null) { 40 | // return true; 41 | // }else { 42 | // return false; 43 | // } 44 | // } 45 | // } 46 | // return false; 47 | // } 48 | // 49 | // 要求以 O(1) 的空间复杂度来求解。 50 | // 51 | // 切成两半,把后半段反转,然后比较两半是否相等。 52 | 53 | public boolean isPalindrome(ListNode head) { 54 | if (head == null || head.next == null) return true; 55 | ListNode slow = head, fast = head.next; 56 | while (fast != null && fast.next != null) { 57 | slow = slow.next; 58 | fast = fast.next.next; 59 | } 60 | 61 | if (fast != null) { // 偶数节点,让 slow 指向下一个节点 62 | slow = slow.next; 63 | } 64 | 65 | cut(head, slow); // 切成两个链表 66 | ListNode l1 = head, l2 = slow; 67 | l2 = reverse(l2); 68 | return isEqual(l1, l2); 69 | } 70 | 71 | private void cut(ListNode head, ListNode cutNode) { 72 | while (head.next != cutNode) head = head.next; 73 | head.next = null; 74 | } 75 | 76 | private ListNode reverse(ListNode head) { 77 | ListNode newHead = null; 78 | while (head != null) { 79 | ListNode nextNode = head.next; 80 | head.next = newHead; 81 | newHead = head; 82 | head = nextNode; 83 | } 84 | return newHead; 85 | } 86 | 87 | private boolean isEqual(ListNode l1, ListNode l2) { 88 | while (l1 != null && l2 != null) { 89 | if (l1.val != l2.val) return false; 90 | l1 = l1.next; 91 | l2 = l2.next; 92 | } 93 | return true; 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/数据结构/链表/归并两个有序的链表.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/19. 5 | */ 6 | public class 归并两个有序的链表 { 7 | 8 | // 链表和树一样,可以用递归方式来定义:链表是空节点,或者有一个值和一个指向下一个链表的指针。因此很多链表问题可以用递归来处理。 9 | // 妙哉妙哉 10 | public ListNode mergeTwoLists2(ListNode l1, ListNode l2) { 11 | if(l1 == null) return l2; 12 | if(l2 == null) return l1; 13 | ListNode newHead = null; 14 | if(l1.val < l2.val){ 15 | newHead = l1; 16 | newHead.next = mergeTwoLists2(l1.next, l2); 17 | } else{ 18 | newHead = l2; 19 | newHead.next = mergeTwoLists2(l1, l2.next); 20 | } 21 | return newHead; 22 | } 23 | public static void main(String[] args) { 24 | ListNode l1 = new ListNode(1); 25 | ListNode l2 = new ListNode(2); 26 | ListNode l3 = new ListNode(4); 27 | ListNode l4 = new ListNode(1); 28 | ListNode l5 = new ListNode(3); 29 | ListNode l6 = new ListNode(4); 30 | l2.next = l3; 31 | l1.next = l2; 32 | 33 | l5.next = l6; 34 | l4.next = l5; 35 | 36 | System.out.println(mergeTwoLists(l1,l4)); 37 | } 38 | public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { 39 | if (l1 == null)return l2; 40 | if (l2 == null)return l1; 41 | ListNode p = l1; 42 | ListNode q = l2; 43 | ListNode h = new ListNode(0); 44 | ListNode op = h; 45 | while (p != null && q != null) { 46 | if (p.val < q.val) { 47 | op.next = new ListNode(p.val); 48 | p = p.next; 49 | op = op.next; 50 | }else if (p.val > q.val) { 51 | op.next = new ListNode(q.val); 52 | q = q.next; 53 | op = op.next; 54 | }else { 55 | op.next = new ListNode(p.val); 56 | op = op.next; 57 | op.next = new ListNode(q.val); 58 | op = op.next; 59 | p = p.next; 60 | q = q.next; 61 | } 62 | } 63 | while (p != null) { 64 | op.next = new ListNode(p.val); 65 | p = p.next; 66 | op = op.next; 67 | } 68 | while (q != null) { 69 | op.next = new ListNode(q.val); 70 | q = q.next; 71 | op = op.next; 72 | } 73 | op.next = null; 74 | return h.next; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/数据结构/链表/找出两个链表的交点.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/4/13. 5 | */ 6 | public class 找出两个链表的交点 { 7 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 8 | if (headA == null || headB == null) { 9 | return null; 10 | } 11 | int len1 = getLength(headA); 12 | int len2 = getLength(headB); 13 | int len = len1 - len2; 14 | //长的 15 | ListNode p = len >= 0 ? headA : headB; 16 | //短的 17 | ListNode q = len >= 0 ? headB : headA; 18 | len = Math.abs(len); 19 | while (len > 0) { 20 | p = p.next; 21 | len --; 22 | } 23 | while (p != q && p != null && q != null) { 24 | p = p.next; 25 | q = q.next; 26 | } 27 | 28 | return p; 29 | } 30 | 31 | public int getLength(ListNode node) { 32 | int cnt = 0; 33 | while (node != null) { 34 | node = node.next; 35 | cnt ++; 36 | } 37 | return cnt; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/数据结构/链表/根据有序链表构造平衡的BST.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | import ADT.TreeNode; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/19. 7 | */ 8 | public class 根据有序链表构造平衡的BST { 9 | //先找到中点作为根节点,递归找中点左右链表的中点,作为左右子树。 10 | //难点在于边界判断,这个不是我写的。 11 | public TreeNode sortedListToBST(ListNode head) { 12 | if (head == null) return null; 13 | int size = size(head); 14 | if (size == 1) return new TreeNode(head.val); 15 | ListNode pre = head, mid = pre.next; 16 | int step = 2; 17 | while (step <= size / 2) { 18 | pre = mid; 19 | mid = mid.next; 20 | step++; 21 | } 22 | pre.next = null; 23 | TreeNode t = new TreeNode(mid.val); 24 | t.left = sortedListToBST(head); 25 | t.right = sortedListToBST(mid.next); 26 | return t; 27 | } 28 | private int size(ListNode node) { 29 | int size = 0; 30 | while (node != null) { 31 | size++; 32 | node = node.next; 33 | } 34 | return size; 35 | } 36 | // public TreeNode sortedListToBST(ListNode head) { 37 | // int cnt = 0; 38 | // ListNode p = head; 39 | // while (p != null) { 40 | // p = p.next; 41 | // cnt ++; 42 | // } 43 | // return setTree(head, 0, cnt); 44 | // } 45 | // public TreeNode setTree(ListNode l,int start,int end) { 46 | // int index = (end - start)/2; 47 | // ListNode p = l; 48 | // ListNode pre = p; 49 | // for (int i = 1;i <= index && p.next != null;i ++) { 50 | // p = p.next; 51 | // pre = p; 52 | // } 53 | // 54 | // TreeNode t = new TreeNode(p.val); 55 | // if (p.next != null) { 56 | // t.right = setTree(l,index + 1, end); 57 | // } 58 | // t.left = setTree(l,start,index - 1); 59 | // return t; 60 | // } 61 | } 62 | -------------------------------------------------------------------------------- /src/数据结构/链表/链表元素按奇偶聚集.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/20. 7 | */ 8 | public class 链表元素按奇偶聚集 { 9 | //是按照元素的次序中的奇偶数,而不是节点值的奇偶数 10 | public ListNode oddEvenList(ListNode head) { 11 | if (head == null)return head; 12 | if (head.next == null)return head; 13 | ListNode even = new ListNode(0); 14 | ListNode odd = new ListNode(0); 15 | ListNode l1 = even; 16 | ListNode l2 = odd; 17 | ListNode p = head; 18 | int cnt = 1; 19 | while (p != null) { 20 | if (cnt % 2 == 0) { 21 | even.next = p; 22 | even = even.next; 23 | }else { 24 | odd.next = p; 25 | odd = odd.next; 26 | } 27 | cnt ++; 28 | p = p.next; 29 | } 30 | even.next = null; 31 | odd.next = l1.next; 32 | return l2.next; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/数据结构/链表/链表十进制求和.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/19. 7 | */ 8 | public class 链表十进制求和 { 9 | // //写错了。链表的递归好烦啊 10 | // public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 11 | // ListNode p = null; 12 | // ListNode q = null; 13 | // int len1 = size(l1); 14 | // int len2 = size(l2); 15 | // if (len1 == len2); 16 | // p = len1 > len2 ? l1:l2; 17 | // q = len1 < len2 ? l1:l2; 18 | // ListNode temp = p; 19 | // int l = len1 - len2; 20 | // while (l > 0) { 21 | // p = p.next; 22 | // l --; 23 | // } 24 | // int over = 0; 25 | // int val = p.val + add(p,q) + q.val; 26 | // if (val >= 10) { 27 | // p.val = val - 10; 28 | // over = 1; 29 | // } 30 | // int res = addsingle(temp, 1); 31 | // if (res == 1) { 32 | // ListNode h = new ListNode(1); 33 | // h.next = temp; 34 | // return h; 35 | // }else { 36 | // return temp; 37 | // } 38 | // } 39 | // public int addsingle(ListNode l,int cnt) { 40 | // if (l.next != null) { 41 | // l.val += addsingle(l.next, cnt); 42 | // } 43 | // if (l.val + cnt >= 10) { 44 | // l.val = l.val + cnt - 10; 45 | // return 1; 46 | // }else { 47 | // l.val = l.val + cnt; 48 | // return 0; 49 | // } 50 | // } 51 | // public int add(ListNode l1,ListNode l2) { 52 | // if (l1.next == null && l2.next == null) { 53 | // int over = l1.val + l2.val - 10; 54 | // 55 | // if (over < 0) { 56 | // l1.val = l1.val + l2.val; 57 | // return 0; 58 | // }else { 59 | // l1.val = over; 60 | // return 1; 61 | // } 62 | // } 63 | // return add(l1.next,l2.next); 64 | // } 65 | // private int size(ListNode node) { 66 | // int size = 0; 67 | // while (node != null) { 68 | // size++; 69 | // node = node.next; 70 | // } 71 | // return size; 72 | // } 73 | 74 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 75 | Stack l1Stack = buildStack(l1); 76 | Stack l2Stack = buildStack(l2); 77 | ListNode head = new ListNode(-1); 78 | int carry = 0; 79 | while (!l1Stack.isEmpty() || !l2Stack.isEmpty() || carry != 0) { 80 | int x = l1Stack.isEmpty() ? 0 : l1Stack.pop(); 81 | int y = l2Stack.isEmpty() ? 0 : l2Stack.pop(); 82 | int sum = x + y + carry; 83 | ListNode node = new ListNode(sum % 10); 84 | node.next = head.next; 85 | head.next = node; 86 | carry = sum / 10; 87 | } 88 | return head.next; 89 | } 90 | 91 | private Stack buildStack(ListNode l) { 92 | Stack stack = new Stack<>(); 93 | while (l != null) { 94 | stack.push(l.val); 95 | l = l.next; 96 | } 97 | return stack; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/数据结构/链表/链表反转.java: -------------------------------------------------------------------------------- 1 | package 数据结构.链表; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/4/19. 7 | */ 8 | public class 链表反转 { 9 | public ListNode reverseList(ListNode head) { 10 | ListNode p = null; 11 | ListNode q = head; 12 | while (q != null) { 13 | ListNode r = q.next; 14 | q.next = p; 15 | p = q; 16 | q = r; 17 | } 18 | return p; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/贪心/买卖股票.java: -------------------------------------------------------------------------------- 1 | package 贪心; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/17. 5 | */ 6 | public class 买卖股票 { 7 | public int maxProfit(int[] prices) { 8 | if(prices.length <=1){ 9 | return 0; 10 | } 11 | int profit = 0; 12 | for(int i=1;iprices[i-1]){ 14 | profit += prices[i]-prices[i-1]; 15 | } 16 | 17 | } 18 | return profit; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/贪心/修改一个数成为非递减数组.java: -------------------------------------------------------------------------------- 1 | package 贪心; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/17. 5 | * 题目描述:判断一个数组能不能只修改一个数就成为非递减数组。 6 | 7 | 在出现 nums[i] < nums[i - 1] 时,需要考虑的是应该修改数组的哪个数, 8 | 使得本次修改能使 i 之前的数组成为非递减数组,并且 不影响后续的操作 。优先考虑令 nums[i - 1] = nums[i],因为如果修改 nums[i] = nums[i - 1] 的话,那么 nums[i] 这个数会变大,那么就有可能比 nums[i + 1] 大,从而影响了后续操作。还有一个比较特别的情况就是 nums[i] < nums[i - 2],只修改 nums[i - 1] = nums[i] 不能令数组成为非递减, 9 | 只能通过修改 nums[i] = nums[i - 1] 才行。 10 | */ 11 | public class 修改一个数成为非递减数组 { 12 | public boolean checkPossibility(int[] nums) { 13 | int count = 0; 14 | for(int i = 0;i < nums.length - 1;i ++) { 15 | if(nums[i] <= nums[i+1]) { 16 | continue; 17 | } 18 | if(i - 1 >= 0 && nums[i+1] < nums[i -1]){ 19 | nums[i+1] = nums[i]; 20 | }else nums[i] = nums[i+1]; 21 | count ++; 22 | } 23 | return count<=1; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/贪心/分配饼干.java: -------------------------------------------------------------------------------- 1 | package 贪心; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 题目描述:每个孩子都有一个满足度,每个饼干都有一个大小,只有饼干的大小大于一个孩子的满足度,该孩子才会获得满足。 7 | * 求解最多可以获得满足的孩子数量。 8 | 9 | 因为最小的孩子最容易得到满足,因此先满足最小孩子。给一个孩子的饼干应当尽量小又能满足该孩子, 10 | 这样大饼干就能拿来给满足度比较大的孩子。 11 | 12 | 贪心算法 13 | */ 14 | public class 分配饼干 { 15 | public int findContentChildren(int[] g, int[] s) { 16 | Arrays.sort(g); 17 | Arrays.sort(s); 18 | int count = 0; 19 | for(int i = 0,j=0;i partitionLabels(String S) { 11 | List ret = new ArrayList<>(); 12 | int[] lastIdxs = new int[26]; 13 | for(int i = 0; i < S.length(); i++) lastIdxs[S.charAt(i) - 'a'] = i; 14 | int start = 0; 15 | while (start end) end = last; 21 | 22 | } 23 | ret.add(end - start +1); 24 | } 25 | return ret; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/贪心/判断是否为子串.java: -------------------------------------------------------------------------------- 1 | package 贪心; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/17. 5 | */ 6 | public class 判断是否为子串 { 7 | public boolean isSubsequence(String s, String t) { 8 | if(s.equals(""))return true; 9 | char []ss = s.toCharArray(); 10 | char []tt = t.toCharArray(); 11 | boolean flag = false; 12 | for(int i=0,j=0;i a[1] - b[1]); 19 | int curPos = points[0][1]; 20 | int ret = 1; 21 | for(int i=1;i() { 16 | public int compare(int[] a, int[] b) { 17 | if(a[0] == b[0]) return a[1] - b[1]; 18 | return b[0] - a[0]; 19 | } 20 | }); 21 | 22 | int n = people.length; 23 | List tmp = new ArrayList<>(); 24 | 25 | for(int i = 0; i < n; i++) { 26 | tmp.add(people[i][1], new int[]{people[i][0], people[i][1]}); 27 | } 28 | 29 | int[][] ret = new int[n][2]; 30 | for(int i = 0; i < n; i++) { 31 | ret[i][0] = tmp.get(i)[0]; 32 | ret[i][1] = tmp.get(i)[1]; 33 | } 34 | return ret; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/贪心/种植花朵.java: -------------------------------------------------------------------------------- 1 | package 贪心; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/17. 5 | * 题目描述:花朵之间至少需要一个单位的间隔。 6 | */ 7 | public class 种植花朵 { 8 | public boolean canPlaceFlowers(int[] flowerbed, int n) { 9 | int cnt = 0; 10 | for(int i = 0;i < flowerbed.length; i++){ 11 | if(flowerbed[i] ==1)continue; 12 | int pre = i == 0 ? 0 : flowerbed[i-1]; 13 | int next = i == flowerbed.length - 1 ? 0 : flowerbed[i+1]; 14 | if(pre == 0 && next == 0) { 15 | flowerbed[i] = 1; 16 | cnt ++; 17 | } 18 | } 19 | return cnt>=n; 20 | } 21 | } 22 | --------------------------------------------------------------------------------