├── 08-动态规划 ├── xx.位运算 ├── dp.md └── src │ └── com │ └── dp │ ├── MaxSubArray.java │ ├── LIS.java │ └── LCSubstring.java ├── Top ├── 08-高频题 │ ├── _252_会议室.java │ ├── _253_会议室_II.java │ ├── _283_移动零.java │ ├── _1_两数之和.java │ ├── _剑指Offer62_圆圈中最后剩下的数字.java │ ├── _7_整数反转.java │ ├── _54_螺旋矩阵.java │ ├── _50_Pow(x, n).java │ ├── _15_三数之和.java │ └── _146_LRU缓存机制_01.java ├── 02-链表 │ ├── _708_循环有序列表的插入.java │ ├── _148_排序链表.java │ ├── ListNode.java │ ├── _23_合并K个排序链表.java │ ├── _141_环形链表.java │ ├── _25_K个一组翻转链表.java │ ├── _206_反转链表.java │ ├── _237_删除链表中的节点.java │ ├── _203_移除链表元素.java │ ├── _21_合并两个有序链表.java │ ├── _138_复制带随机指针的链表.java │ ├── _86_分隔链表.java │ ├── _2_两数相加.java │ ├── _00_必须能默写.java │ ├── _160_相交链表.java │ └── _234_回文链表.java ├── 03-栈&队列 │ ├── TreeNode.java │ ├── _42_接雨水.java │ ├── 面试题_09_用两个栈实现队列.java │ ├── _20_有效的括号.java │ ├── _面试题_03_04_化栈为队.java │ ├── _232_用栈实现队列.java │ ├── _739_每日温度.java │ └── _239_滑动窗口最大值.java ├── 04-字符串 │ ├── _5_最长回文子串.java │ ├── _32_最长有效括号.java │ ├── _1048_最长字符串链.java │ ├── _72_编辑距离.java │ ├── _面试题_01_09_字符串轮转.java │ ├── _242_有效的字母异位词.java │ ├── _1143_最长公共子序列.java │ ├── _572_另一个树的子树.java │ └── _151_翻转字符串里的单词.java ├── 07-DFS │ ├── _93_复原IP地址.java │ ├── _39_组合总和.java │ ├── _52_N皇后II.java │ ├── _112_路径总和.java │ ├── _51_N皇后.java │ ├── _113_路径总和II.java │ ├── _46_全排列_2.java │ ├── _17_电话号码的字母组合.java │ ├── _46_全排列_1.java │ ├── _47_全排列II.java │ ├── _22_括号生成.java │ └── _46_全排列_0.java ├── 01-数组 │ ├── _164_最大间距.java │ ├── _88_合并两个有序数组.java │ ├── _75_颜色分类.java │ ├── _面试题_16_16_部分排序.java │ └── _977_有序数组的平方.java ├── 05-动态规划 │ ├── _面试题47_礼物的最大价值.java │ ├── _121_买卖股票的最佳时机.java │ └── _72_编辑距离.java └── 06-二叉树 │ ├── _236_二叉树的最近公共祖先.java │ └── _333_最大BST子树.java ├── Images ├── 001.png ├── desc.png ├── memo.png ├── _67.二进制求和.png ├── _739_每日温度_backward0.png └── _739_每日温度_backward1.png ├── Leetcode ├── _137_只出现一次的数字II.java ├── Array&String │ ├── _14_最长公共前缀.java │ ├── _28_实现strStr().java │ ├── _66.加一.java │ ├── _118.杨辉三角.java │ ├── _747.至少是其他数字两倍的最大数.java │ ├── _724.寻找数组的中心索引.java │ ├── _498.对角线遍历.java │ ├── _54.螺旋矩阵.java │ └── _989.数组形式的整数加法.java ├── _136_只出现一次的数字.java ├── Stack&Queue │ ├── _556. 下一个更大元素 III.java │ ├── _739. 每日温度.java │ ├── _503. 下一个更大元素 II.java │ ├── 深度优先搜索(DFS)模板.md │ ├── _279. 完全平方数.java │ ├── _130. 被围绕的区域.java │ ├── _232. 用栈实现队列.java │ ├── _496. 下一个更大元素 I.java │ ├── _1021. 删除最外层的括号.java │ ├── _155. 最小栈.java │ ├── _1047. 删除字符串中的所有相邻重复项.java │ ├── _316. 去除重复字母.java │ ├── _150. 逆波兰表达式求值.java │ └── 广度优先搜索(BFS)模板.md ├── _1143_最长公共子序列.java └── _300_最长上升子序列.java ├── 04-递归 ├── Recursion.md └── src │ └── com │ └── recursion │ ├── Times.java │ └── Fib.java ├── 01-排序 └── src │ ├── com │ ├── tools │ │ ├── Asserts.java │ │ └── Times.java │ ├── Student.java │ └── sort │ │ ├── cmp │ │ ├── BubbleSort2.java │ │ ├── BubbleSort3.java │ │ ├── BubbleSort1.java │ │ └── SelectionSort.java │ │ └── Sort.java │ └── Main.java ├── 11-字符串 └── src │ ├── com │ ├── tools │ │ ├── Asserts.java │ │ └── Times.java │ └── sequence │ │ ├── BruteForce02.java │ │ ├── BruteForce01.java │ │ └── KMP.java │ └── Main.java ├── .gitignore ├── 剑指Offer ├── _面试题47_礼物的最大价值.java ├── _面试题10_II_青蛙跳台阶问题.java ├── _面试题58_II_左旋转字符串.java ├── _面试题06_从尾到头打印链表.java ├── _面试题40_最小的k个数.java ├── _面试题21_调整数组顺序使奇数位于偶数前面.java ├── _面试题63_股票的最大利润.java ├── _面试题22_链表中倒数第k个节点.java ├── _面试题10_I_斐波那契数列.java ├── _面试题14_I_剪绳子.java ├── _面试题25_合并两个排序的链表.java ├── _面试题46_把数字翻译成字符串.java ├── _面试题57_和为s的两个数字.java ├── _面试题18_删除链表的节点.java ├── _面试题61_扑克牌中的顺子.java ├── _面试题62_圆圈中最后剩下的数字.java ├── _面试题03_数组中重复的数字.java ├── _面试题57-II_和为s的连续正数序列.java ├── _面试题50_第一个只出现一次的字符.java ├── _面试题09_用两个栈实现队列.java ├── _面试题38_字符串的排列.java ├── _面试题24_反转链表.java ├── _面试题52_两个链表的第一个公共节点.java ├── _面试题39_数组中出现次数超过一半的数字.java ├── 面试题56_I_数组中数字出现的次数.java ├── _面试题13_机器人的运动范围.java └── _面试题59_II_队列的最大值.java ├── 00.数据结构 └── src │ ├── Queue.java │ ├── Stack.java │ ├── Deque.java │ ├── list │ ├── AbstractList.java │ └── List.java │ ├── circle │ ├── CircleQueue.java │ └── CircleDeque.java │ └── Main.java ├── 程序员面试金典 ├── _面试题0812_八皇后.java └── _面试题0811_硬币.java ├── email.sh ├── README.md └── LICENSE /08-动态规划/xx.位运算: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Top/08-高频题/_252_会议室.java: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Top/08-高频题/_253_会议室_II.java: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Top/02-链表/_708_循环有序列表的插入.java: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Top/02-链表/_148_排序链表.java: -------------------------------------------------------------------------------- 1 | public class _148_排序链表 { 2 | 3 | } -------------------------------------------------------------------------------- /Images/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrabMen/DataStructureAndAlgorithms-365Days/HEAD/Images/001.png -------------------------------------------------------------------------------- /Images/desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrabMen/DataStructureAndAlgorithms-365Days/HEAD/Images/desc.png -------------------------------------------------------------------------------- /Images/memo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrabMen/DataStructureAndAlgorithms-365Days/HEAD/Images/memo.png -------------------------------------------------------------------------------- /Leetcode/_137_只出现一次的数字II.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int singleNumber(int[] nums) { 3 | 4 | } 5 | } -------------------------------------------------------------------------------- /Images/_67.二进制求和.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrabMen/DataStructureAndAlgorithms-365Days/HEAD/Images/_67.二进制求和.png -------------------------------------------------------------------------------- /Leetcode/Array&String/_14_最长公共前缀.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public String longestCommonPrefix(String[] strs) { 3 | 4 | } 5 | } -------------------------------------------------------------------------------- /Images/_739_每日温度_backward0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrabMen/DataStructureAndAlgorithms-365Days/HEAD/Images/_739_每日温度_backward0.png -------------------------------------------------------------------------------- /Images/_739_每日温度_backward1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrabMen/DataStructureAndAlgorithms-365Days/HEAD/Images/_739_每日温度_backward1.png -------------------------------------------------------------------------------- /08-动态规划/dp.md: -------------------------------------------------------------------------------- 1 | 1. 定义状态(状态是原问题、子问题的解) 2 | 比如定义 dp(i) 的含义 3 | 4 | 2. 设置初始状态(边界) 5 | 比如设置 dp(0) 的值 6 | 7 | 3. 确定状态转移方程 8 | 比如确定 dp(i) 和 dp(i – 1) 的关系 9 | 10 | 11 | -------------------------------------------------------------------------------- /Top/02-链表/ListNode.java: -------------------------------------------------------------------------------- 1 | 2 | public class ListNode { 3 | public int val; 4 | public ListNode next; 5 | 6 | public ListNode(int x) { 7 | val = x; 8 | } 9 | } -------------------------------------------------------------------------------- /04-递归/Recursion.md: -------------------------------------------------------------------------------- 1 | # 递归(Recursion) 2 | 3 | ## 函数的递归调用过程 4 | 5 | * 如果递归调用没有终止,将会一直消耗栈空间,最终导致栈内存溢出(Stack Overflow) 6 | * 因此必须有一个明确的结束递归的条件 (边界调节/递归基) 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Top/03-栈&队列/TreeNode.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | public class TreeNode { 5 | public int val; 6 | public TreeNode left; 7 | public TreeNode right; 8 | 9 | public TreeNode(int x) { 10 | val = x; 11 | } 12 | } -------------------------------------------------------------------------------- /01-排序/src/com/tools/Asserts.java: -------------------------------------------------------------------------------- 1 | package com.tools; 2 | 3 | public class Asserts { 4 | public static void test(boolean value) { 5 | try { 6 | if (!value) throw new Exception("测试未通过"); 7 | } catch (Exception e) { 8 | e.printStackTrace(); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /11-字符串/src/com/tools/Asserts.java: -------------------------------------------------------------------------------- 1 | package com.tools; 2 | 3 | public class Asserts { 4 | public static void test(boolean value) { 5 | try { 6 | if (!value) throw new Exception("测试未通过"); 7 | } catch (Exception e) { 8 | e.printStackTrace(); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /01-排序/src/com/Student.java: -------------------------------------------------------------------------------- 1 | 2 | package com; 3 | 4 | public class Student implements Comparable { 5 | public int score; 6 | public int age; 7 | 8 | public Student(int score, int age) { 9 | this.score = score; 10 | this.age = age; 11 | } 12 | 13 | @Override 14 | public int compareTo(Student o) { 15 | return age - o.age; 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /Top/04-字符串/_5_最长回文子串.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 3 | * 4 | * 示例 1: 5 | * 6 | * 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。 示例 2: 7 | * 8 | * 输入: "cbbd" 输出: "bb" 9 | * 10 | * 来源:力扣(LeetCode) 11 | * 链接:https://leetcode-cn.com/problems/longest-palindromic-substring 12 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 13 | * 14 | * 15 | * 16 | */ 17 | public class _5_最长回文子串 { 18 | 19 | } -------------------------------------------------------------------------------- /11-字符串/src/Main.java: -------------------------------------------------------------------------------- 1 | import com.sequence.KMP; 2 | import com.tools.Asserts; 3 | 4 | public class Main { 5 | 6 | public static void main(String[] args) { 7 | Asserts.test(KMP.indexOf("Hello World", "H") == 0); 8 | Asserts.test(KMP.indexOf("Hello World", "d") == 10); 9 | Asserts.test(KMP.indexOf("Hello World", "or") == 7); 10 | Asserts.test(KMP.indexOf("Hello World", "abc") == -1); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Top/03-栈&队列/_42_接雨水.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 3 | * 4 | * 5 | * 6 | * 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 7 | * Marcos 贡献此图。 8 | * 9 | * 示例: 10 | * 11 | * 输入: [0,1,0,2,1,0,1,3,2,1,2,1] 输出: 6 12 | * 13 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/trapping-rain-water 14 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 15 | * 16 | * 17 | * 18 | */ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | 26 | # Mac OS file 27 | *.DS_Store 28 | 29 | #VSCode file git 30 | *.vscode/ 31 | 32 | -------------------------------------------------------------------------------- /Top/04-字符串/_32_最长有效括号.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 4 | * 5 | * 示例 1: 6 | * 7 | * 输入: "(()" 输出: 2 解释: 最长有效括号子串为 "()" 示例 2: 8 | * 9 | * 输入: ")()())" 输出: 4 解释: 最长有效括号子串为 "()()" 10 | * 11 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/longest-valid-parentheses 12 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 13 | * 14 | * 15 | */ 16 | 17 | class Solution { 18 | public int longestValidParentheses(String s) { 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /Top/07-DFS/_93_复原IP地址.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。 3 | 4 | 有效的 IP 地址正好由四个整数(每个整数位于 0 到 255 之间组成),整数之间用 '.' 分隔。 5 | 6 |   7 | 8 | 示例: 9 | 10 | 输入: "25525511135" 11 | 输出: ["255.255.11.135", "255.255.111.35"] 12 | 13 | 来源:力扣(LeetCode) 14 | 链接:https://leetcode-cn.com/problems/restore-ip-addresses 15 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 16 | * 17 | * 18 | * 19 | * 20 | */ 21 | 22 | 23 | class Solution { 24 | public List restoreIpAddresses(String s) { 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题47_礼物的最大价值.java: -------------------------------------------------------------------------------- 1 | 2 | class Solution { 3 | public int maxValue(int[][] grid) { 4 | if (grid == null) 5 | return 0; 6 | 7 | int rc = grid.length; 8 | int cc = grid[0].length; 9 | int[][] dp = new int[rc + 1][cc + 1]; 10 | 11 | for (int i = 1; i <= rc; i++) { 12 | for (int j = 1; j <= cc; j++) { 13 | dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1]; 14 | } 15 | } 16 | return dp[rc][cc]; 17 | } 18 | } -------------------------------------------------------------------------------- /00.数据结构/src/Queue.java: -------------------------------------------------------------------------------- 1 | 2 | import list.LinkedList; 3 | import list.List; 4 | 5 | public class Queue { 6 | private List list = new LinkedList<>(); 7 | 8 | public int size() { 9 | return list.size(); 10 | } 11 | 12 | public boolean isEmpty() { 13 | return list.isEmpty(); 14 | } 15 | 16 | public void clear() { 17 | list.clear(); 18 | } 19 | 20 | public void enQueue(E element) { 21 | list.add(element); 22 | } 23 | 24 | public E deQueue() { 25 | return list.remove(0); 26 | } 27 | 28 | public E front() { 29 | return list.get(0); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Top/02-链表/_23_合并K个排序链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。 3 | * 4 | * 示例: 5 | * 6 | * 输入: [   1->4->5,   1->3->4,   2->6 ] 输出: 1->1->2->3->4->4->5->6 7 | * 8 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/merge-k-sorted-lists 9 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 10 | * 11 | * 12 | */ 13 | // Definition for singly-linked list. 14 | public class ListNode { 15 | int val; 16 | ListNode next; 17 | 18 | ListNode(int x) { 19 | val = x; 20 | } 21 | } 22 | 23 | class Solution { 24 | public ListNode mergeKLists(ListNode[] lists) { 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /Top/01-数组/_164_最大间距.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。 4 | * 5 | * 如果数组元素个数小于 2,则返回 0。 6 | * 7 | * 示例 1: 8 | * 9 | * 输入: [3,6,9,1] 输出: 3 解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。 10 | * 示例 2: 11 | * 12 | * 输入: [10] 输出: 0 解释: 数组元素个数小于 2,因此返回 0。 说明: 13 | * 14 | * 你可以假设数组中所有元素都是非负整数,且数值在 32 位有符号整数范围内。 请尝试在线性时间复杂度和空间复杂度的条件下解决此问题。 15 | * 16 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/maximum-gap 17 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 18 | * 19 | * 20 | */ 21 | 22 | class Solution { 23 | public int maximumGap(int[] nums) { 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题10_II_青蛙跳台阶问题.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 3 | * 4 | * 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 5 | * 6 | * 示例 1: 7 | * 8 | * 输入:n = 2 输出:2 示例 2: 9 | * 10 | * 输入:n = 7 输出:21 提示: 11 | * 12 | * 0 <= n <= 100 13 | * 14 | * 来源:力扣(LeetCode) 15 | * 链接:https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof 16 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 17 | * 18 | */ 19 | class Solution { 20 | public int numWays(int n) { 21 | if (n <= 2) 22 | return n; 23 | return numWays(n - 1) + numWays(n - 2); 24 | } 25 | } -------------------------------------------------------------------------------- /00.数据结构/src/Stack.java: -------------------------------------------------------------------------------- 1 | 2 | import list.ArrayList; 3 | import list.List; 4 | 5 | public class Stack { 6 | private List list = new ArrayList<>(); 7 | public void clear() { 8 | list.clear(); 9 | } 10 | 11 | public int size() { 12 | return list.size(); 13 | } 14 | 15 | public boolean isEmpty() { 16 | return list.isEmpty(); 17 | } 18 | 19 | public void push(E element) { 20 | list.add(element); 21 | } 22 | 23 | 24 | public E pop() { 25 | return list.remove(list.size() - 1); 26 | } 27 | 28 | 29 | public E top() { 30 | return list.get(list.size() - 1); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Leetcode/_136_只出现一次的数字.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 4 | * 5 | * 说明: 6 | * 7 | * 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 8 | * 9 | * 示例 1: 10 | * 11 | * 输入: [2,2,1] 输出: 1 示例 2: 12 | * 13 | * 输入: [4,1,2,1,2] 输出: 4 14 | * 15 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/single-number 16 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 17 | * 18 | * 19 | * 20 | */ 21 | 22 | class Solution { 23 | public int singleNumber(int[] nums) { 24 | 25 | for (int i = 1; i < nums.length; i++) { 26 | nums[0] ^= nums[i]; 27 | } 28 | return nums[0]; 29 | } 30 | } -------------------------------------------------------------------------------- /程序员面试金典/_面试题0812_八皇后.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 设计一种算法,打印 N 皇后在 N × N 3 | * 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。 4 | * 5 | * 注意:本题相对原题做了扩展 6 | * 7 | * 示例: 8 | * 9 | * 输入:4 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] 解释: 4 10 | * 皇后问题存在如下两个不同的解法。 [  [".Q..",  // 解法 1   "...Q",   "Q...",   "..Q."], 11 | * 12 | *  ["..Q.",  // 解法 2   "Q...",   "...Q",   ".Q.."] ] 13 | * 14 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/eight-queens-lcci 15 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 16 | * 17 | * 18 | * 19 | */ 20 | 21 | class Solution { 22 | public List> solveNQueens(int n) { 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /01-排序/src/com/sort/cmp/BubbleSort2.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * ◼ 执行流程(本课程统一以升序为例子) 4 | * 5 | * 1 从头开始比较每一对相邻元素,如果第1个比第2个大,就交换它们的位置 6 | * 7 | * ✓ 执行完一轮后,最末尾那个元素就是最大的元素 8 | * 9 | * 2 忽略 1 中曾经找到的最大元素,重复执行步骤 1,直到全部元素有序 10 | */ 11 | package com.sort.cmp; 12 | 13 | import com.sort.Sort; 14 | 15 | public class BubbleSort2> extends Sort { 16 | 17 | @Override 18 | protected void sort() { 19 | for (int end = array.length - 1; end > 0; end--) { 20 | boolean sorted = true; 21 | for (int begin = 1; begin <= end; begin++) { 22 | if (cmp(begin, begin - 1) < 0) { 23 | swap(begin, begin - 1); 24 | sorted = false; 25 | } 26 | } 27 | if(sorted) break; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题58_II_左旋转字符串.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。 3 | * 4 | *   5 | * 6 | * 示例 1: 7 | * 8 | * 输入: s = "abcdefg", k = 2 输出: "cdefgab" 示例 2: 9 | * 10 | * 输入: s = "lrloseumgh", k = 6 输出: "umghlrlose"   11 | * 12 | * 限制: 13 | * 14 | * 1 <= k < s.length <= 10000 15 | * 16 | * 来源:力扣(LeetCode) 17 | * 链接:https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof 18 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 19 | * 20 | * 21 | * 22 | * 23 | */ 24 | 25 | class Solution { 26 | public String reverseLeftWords(String s, int n) { 27 | return s.substring(n, s.length()) + s.substring(0, n); 28 | } 29 | } -------------------------------------------------------------------------------- /Top/02-链表/_141_环形链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * 5 | * 6 | * 7 | */ 8 | // Definition for singly-linked list. 9 | class ListNode { 10 | int val; 11 | ListNode next; 12 | 13 | ListNode(int x) { 14 | val = x; 15 | next = null; 16 | } 17 | } 18 | 19 | public class Solution { 20 | public boolean hasCycle(ListNode head) { 21 | if (head == null || head.next == null) 22 | return false; 23 | ListNode slow = head, fast = head.next; 24 | while (fast != slow) { 25 | if (fast == null || fast.next == null) 26 | return false; 27 | fast = fast.next; 28 | slow = slow.next.next; 29 | } 30 | return true; 31 | } 32 | } -------------------------------------------------------------------------------- /01-排序/src/com/sort/cmp/BubbleSort3.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * ◼ 执行流程(本课程统一以升序为例子) 4 | * 5 | * 1 从头开始比较每一对相邻元素,如果第1个比第2个大,就交换它们的位置 6 | * 7 | * ✓ 执行完一轮后,最末尾那个元素就是最大的元素 8 | * 9 | * 2 忽略 1 中曾经找到的最大元素,重复执行步骤 1,直到全部元素有序 10 | */ 11 | package com.sort.cmp; 12 | 13 | import com.sort.Sort; 14 | 15 | public class BubbleSort3> extends Sort { 16 | 17 | @Override 18 | protected void sort() { 19 | for (int end = array.length - 1; end > 0; end--) { 20 | //如果数组部分有序,则for循环需要对有序部分进行处理 21 | int sortedIdx = 1; 22 | for (int begin = 1; begin <= end; begin++) { 23 | if (cmp(begin, begin - 1) < 0) { 24 | swap(begin, begin - 1); 25 | sortedIdx = begin; 26 | } 27 | } 28 | end = sortedIdx; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Top/07-DFS/_39_组合总和.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 4 | 5 | candidates 中的数字可以无限制重复被选取。 6 | 7 | 说明: 8 | 9 | 所有数字(包括 target)都是正整数。 10 | 解集不能包含重复的组合。  11 | 示例 1: 12 | 13 | 输入: candidates = [2,3,6,7], target = 7, 14 | 所求解集为: 15 | [ 16 | [7], 17 | [2,2,3] 18 | ] 19 | 示例 2: 20 | 21 | 输入: candidates = [2,3,5], target = 8, 22 | 所求解集为: 23 | [ 24 |   [2,2,2,2], 25 |   [2,3,3], 26 |   [3,5] 27 | ] 28 | 29 | 来源:力扣(LeetCode) 30 | 链接:https://leetcode-cn.com/problems/combination-sum 31 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 32 | * 33 | * 34 | */ 35 | 36 | 37 | 38 | 39 | class Solution { 40 | public List> combinationSum(int[] candidates, int target) { 41 | 42 | } 43 | } -------------------------------------------------------------------------------- /Top/07-DFS/_52_N皇后II.java: -------------------------------------------------------------------------------- 1 | /** 2 | * n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 3 | 4 | 5 | 6 | 上图为 8 皇后问题的一种解法。 7 | 8 | 给定一个整数 n,返回 n 皇后不同的解决方案的数量。 9 | 10 | 示例: 11 | 12 | 输入: 4 13 | 输出: 2 14 | 解释: 4 皇后问题存在如下两个不同的解法。 15 | [ 16 |  [".Q..",  // 解法 1 17 |   "...Q", 18 |   "Q...", 19 |   "..Q."], 20 | 21 |  ["..Q.",  // 解法 2 22 |   "Q...", 23 |   "...Q", 24 |   ".Q.."] 25 | ] 26 |   27 | 28 | 提示: 29 | 30 | 皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一或七步,可进可退。(引用自 百度百科 - 皇后 ) 31 | 32 | 来源:力扣(LeetCode) 33 | 链接:https://leetcode-cn.com/problems/n-queens-ii 34 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 35 | * 36 | * 37 | * 38 | */ 39 | 40 | class Solution { 41 | public int totalNQueens(int n) { 42 | 43 | } 44 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题06_从尾到头打印链表.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | // Definition for singly-linked list. 4 | public class ListNode { 5 | int val; 6 | ListNode next; 7 | 8 | ListNode(int x) { 9 | val = x; 10 | } 11 | } 12 | 13 | class Solution { 14 | public int[] reversePrint(ListNode head) { 15 | if (head == null) 16 | return new int[0]; 17 | 18 | Stack stack = new Stack<>(); 19 | while (head != null) { 20 | stack.push(head); 21 | head = head.next; 22 | } 23 | 24 | int[] result = new int[stack.size()]; 25 | for (int i = 0; i < result.length; i++) { 26 | result[i] = stack.pop().val; 27 | } 28 | return result; 29 | } 30 | } -------------------------------------------------------------------------------- /Top/07-DFS/_112_路径总和.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。 4 | 5 | 说明: 叶子节点是指没有子节点的节点。 6 | 7 | 示例:  8 | 给定如下二叉树,以及目标和 sum = 22, 9 | 10 | 5 11 | / \ 12 | 4 8 13 | / / \ 14 | 11 13 4 15 | / \ \ 16 | 7 2 1 17 | 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。 18 | 19 | 来源:力扣(LeetCode) 20 | 链接:https://leetcode-cn.com/problems/path-sum 21 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 22 | * 23 | * 24 | * 25 | * 26 | */ 27 | 28 | /** 29 | * Definition for a binary tree node. public class TreeNode { int val; TreeNode 30 | * left; TreeNode right; TreeNode(int x) { val = x; } } 31 | */ 32 | class Solution { 33 | public boolean hasPathSum(TreeNode root, int sum) { 34 | 35 | } 36 | } -------------------------------------------------------------------------------- /01-排序/src/com/sort/cmp/BubbleSort1.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * ◼ 执行流程(本课程统一以升序为例子) 4 | * 5 | * 1 从头开始比较每一对相邻元素,如果第1个比第2个大,就交换它们的位置 6 | * 7 | * ✓ 执行完一轮后,最末尾那个元素就是最大的元素 8 | * 9 | * 2 忽略 1 中曾经找到的最大元素,重复执行步骤 1,直到全部元素有序 10 | */ 11 | package com.sort.cmp; 12 | 13 | import com.sort.Sort; 14 | 15 | public class BubbleSort1> extends Sort { 16 | 17 | @Override 18 | protected void sort() { 19 | for (int end = array.length - 1; end > 0; end--) { 20 | for (int begin = 1; begin <= end; begin++) { 21 | // if (array[begin] < array[begin - 1]) { 22 | // int tmp = array[begin]; 23 | // array[begin] = array[begin - 1]; 24 | // array[begin - 1] = tmp; 25 | // } 26 | 27 | if (cmp(begin, begin - 1) < 0) { 28 | swap(begin, begin - 1); 29 | } 30 | } 31 | } 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /Top/08-高频题/_283_移动零.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 3 | * 4 | * 示例: 5 | * 6 | * 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 7 | * 8 | * 必须在原数组上操作,不能拷贝额外的数组。 尽量减少操作次数。 9 | * 10 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/move-zeroes 11 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 12 | * 13 | * 14 | * 15 | * 16 | * 17 | */ 18 | 19 | class Solution { 20 | public void moveZeroes(int[] nums) { 21 | // 数组 双指针 22 | if (nums == null) 23 | return; 24 | for (int i = 0, cur = 0; i < nums.length; i++) { 25 | if (nums[i] == 0) 26 | continue; 27 | if (cur != i) { 28 | nums[cur] = nums[i]; 29 | nums[i] = 0; 30 | } 31 | cur++; 32 | } 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /Top/02-链表/_25_K个一组翻转链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 3 | * 4 | * k 是一个正整数,它的值小于或等于链表的长度。 5 | * 6 | * 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 7 | * 8 | * 示例: 9 | * 10 | * 给你这个链表:1->2->3->4->5 11 | * 12 | * 当 k = 2 时,应当返回: 2->1->4->3->5 13 | * 14 | * 当 k = 3 时,应当返回: 3->2->1->4->5 15 | * 16 | * 说明: 17 | * 18 | * 你的算法只能使用常数的额外空间。 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。 19 | * 20 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group 21 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 22 | * 23 | */ 24 | // Definition for singly-linked list. 25 | public class ListNode { 26 | int val; 27 | ListNode next; 28 | 29 | ListNode(int x) { 30 | val = x; 31 | } 32 | } 33 | 34 | class Solution { 35 | public ListNode reverseKGroup(ListNode head, int k) { 36 | 37 | } 38 | } -------------------------------------------------------------------------------- /Top/04-字符串/_1048_最长字符串链.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给出一个单词列表,其中每个单词都由小写英文字母组成。 4 | * 5 | * 如果我们可以在 word1 的任何地方添加一个字母使其变成 word2,那么我们认为 word1 是 word2 的前身。例如,"abc" 是 "abac" 的前身。 6 | * 7 | * 词链是单词 [word_1, word_2, ..., word_k] 组成的序列,k >= 8 | * 1,其中 word_1 是 word_2 的前身,word_2 是 word_3 的前身,依此类推。 9 | * 10 | * 从给定单词列表 words 中选择单词组成词链,返回词链的最长可能长度。   11 | * 12 | * 示例: 13 | * 14 | * 输入:["a","b","ba","bca","bda","bdca"] 输出:4 解释:最长单词链之一为 "a","ba","bda","bdca"。 15 | *   16 | * 17 | * 提示: 18 | * 19 | * 1 <= words.length <= 1000 1 <= words[i].length <= 16 words[i] 仅由小写英文字母组成。 20 | * 21 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/longest-string-chain 22 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 23 | * 24 | * 25 | * 26 | */ 27 | 28 | class Solution { 29 | public int longestStrChain(String[] words) { 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /Top/04-字符串/_72_编辑距离.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。 3 | * 4 | * 你可以对一个单词进行如下三种操作: 5 | * 6 | * 插入一个字符 删除一个字符 替换一个字符   7 | * 8 | * 示例 1: 9 | * 10 | * 输入:word1 = "horse", word2 = "ros" 输出:3 解释: horse -> rorse (将 'h' 替换为 'r') 11 | * rorse -> rose (删除 'r') rose -> ros (删除 'e') 示例 2: 12 | * 13 | * 输入:word1 = "intention", word2 = "execution" 输出:5 解释: intention -> inention 14 | * (删除 't') inention -> enention (将 'i' 替换为 'e') enention -> exention (将 'n' 替换为 15 | * 'x') exention -> exection (将 'n' 替换为 'c') exection -> execution (插入 'u') 16 | * 17 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/edit-distance 18 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 19 | * 20 | * 21 | * 22 | */ 23 | class Solution { 24 | public int minDistance(String word1, String word2) { 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /Top/04-字符串/_面试题_01_09_字符串轮转.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。 4 | * 5 | * 示例1: 6 | * 7 | * 输入:s1 = "waterbottle", s2 = "erbottlewat" 输出:True 示例2: 8 | * 9 | * 输入:s1 = "aa", s2 = "aba" 输出:False 提示: 10 | * 11 | * 字符串长度在[0, 100000]范围内。 说明: 12 | * 13 | * 你能只调用一次检查子串的方法吗? 14 | * 15 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/string-rotation-lcci 16 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 17 | * 18 | * 19 | * 20 | */ 21 | class Solution { 22 | public boolean isFlipedString(String s1, String s2) { 23 | if (s1 == null || s2 == null) 24 | return false; 25 | if (s1.length() != s2.length()) 26 | return false; 27 | //可以将contains使用kmp算法判断是否为子串 28 | return (s1 + s1).contains(s2); 29 | } 30 | } -------------------------------------------------------------------------------- /email.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Cannot create a new backup. 4 | # A previous backup already exists in refs/original/ 5 | # Force overwriting the backup with -f 6 | # 如果之前曾经执行过 git filter-branch 命令,在 refs/original/ 会有一个备份,这个时候需要删除备份,然后执行接下来的操作即可 7 | git update-ref -d refs/original/refs/heads/master 8 | 9 | git filter-branch --env-filter ' 10 | 11 | OLD_EMAIL="crabman@guoqiangdeMacBook-Pro-2.local" 12 | CORRECT_NAME="CrabMen" 13 | CORRECT_EMAIL="tobecrabman@163.com" 14 | 15 | if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ] 16 | then 17 | export GIT_COMMITTER_NAME="$CORRECT_NAME" 18 | export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL" 19 | fi 20 | if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ] 21 | then 22 | export GIT_AUTHOR_NAME="$CORRECT_NAME" 23 | export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL" 24 | fi 25 | ' --tag-name-filter cat -- --branches --tags 26 | -------------------------------------------------------------------------------- /Top/07-DFS/_51_N皇后.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 4 | 5 | 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 6 | 7 | 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 8 | 9 | 示例: 10 | 11 | 输入: 4 12 | 输出: [ 13 | [".Q..", // 解法 1 14 | "...Q", 15 | "Q...", 16 | "..Q."], 17 | 18 | ["..Q.", // 解法 2 19 | "Q...", 20 | "...Q", 21 | ".Q.."] 22 | ] 23 | 解释: 4 皇后问题存在两个不同的解法。 24 |   25 | 26 | 提示: 27 | 28 | 皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一到七步,可进可退。(引用自 百度百科 - 皇后 ) 29 | 30 | 来源:力扣(LeetCode) 31 | 链接:https://leetcode-cn.com/problems/n-queens 32 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 33 | * 34 | * 35 | * 36 | */ 37 | 38 | 39 | /** 40 | * 41 | * 42 | * 43 | * 44 | */ 45 | class Solution { 46 | public List> solveNQueens(int n) { 47 | 48 | } 49 | } -------------------------------------------------------------------------------- /Top/02-链表/_206_反转链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 反转一个单链表。 3 | * 4 | * 示例: 5 | * 6 | * 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 进阶: 7 | * 你可以迭代或递归地反转链表。你能否用两种方法解决这道题? 8 | * 9 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/reverse-linked-list 10 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 11 | * 12 | * 13 | */ 14 | 15 | // Definition for singly-linked list. 16 | public class ListNode { 17 | int val; 18 | ListNode next; 19 | 20 | ListNode(int x) { 21 | val = x; 22 | } 23 | } 24 | 25 | class Solution { 26 | public ListNode reverseList(ListNode head) { 27 | ListNode prev = null; 28 | while (head != null) { 29 | ListNode tempNext = head.next; 30 | head.next = prev; 31 | prev = head; 32 | head = tempNext; 33 | } 34 | return prev; 35 | } 36 | } -------------------------------------------------------------------------------- /00.数据结构/src/Deque.java: -------------------------------------------------------------------------------- 1 | 2 | import list.LinkedList; 3 | import list.List; 4 | 5 | public class Deque { 6 | private List list = new LinkedList<>(); 7 | 8 | public int size() { 9 | return list.size(); 10 | } 11 | 12 | public boolean isEmpty() { 13 | return list.isEmpty(); 14 | } 15 | 16 | public void clear() { 17 | list.clear(); 18 | } 19 | 20 | public void enQueueRear(E element) { 21 | list.add(element); 22 | } 23 | 24 | public E deQueueFront() { 25 | return list.remove(0); 26 | } 27 | 28 | public void enQueueFront(E element) { 29 | list.add(0, element); 30 | } 31 | 32 | public E deQueueRear() { 33 | return list.remove(list.size() - 1); 34 | } 35 | 36 | public E front() { 37 | return list.get(0); 38 | } 39 | 40 | public E rear() { 41 | return list.get(list.size() - 1); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /剑指Offer/_面试题40_最小的k个数.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。 3 | * 4 | *   5 | * 6 | * 示例 1: 7 | * 8 | * 输入:arr = [3,2,1], k = 2 输出:[1,2] 或者 [2,1] 示例 2: 9 | * 10 | * 输入:arr = [0,1,2,1], k = 1 输出:[0]   11 | * 12 | * 限制: 13 | * 14 | * 0 <= k <= arr.length <= 10000 0 <= arr[i] <= 10000 15 | * 16 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof 17 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 18 | * 19 | * 20 | * 21 | * 22 | */ 23 | 24 | class Solution { 25 | public int[] getLeastNumbers(int[] arr, int k) { 26 | if (arr == null || arr.length == 0 || k == 0) 27 | return new int[0]; 28 | Arrays.sort(arr); 29 | int[] result = new int[k]; 30 | for (int i = 0; i < k; i++) 31 | result[i] = arr[i]; 32 | return result; 33 | } 34 | } -------------------------------------------------------------------------------- /01-排序/src/com/sort/cmp/SelectionSort.java: -------------------------------------------------------------------------------- 1 | package com.sort.cmp; 2 | 3 | import com.sort.Sort; 4 | 5 | public class SelectionSort> extends Sort { 6 | 7 | @Override 8 | protected void sort() { 9 | 10 | // for (int end = array.length - 1; end > 0; end--) { 11 | // int max = 0; 12 | // for (int begin = 1; begin <= end; begin++) { 13 | // if (cmp(max, begin) <= 0) { 14 | // max = begin; 15 | // } 16 | // } 17 | // swap(max, end); 18 | // } 19 | 20 | for (int end = array.length - 1; end > 0; end--) { 21 | int max = 0; 22 | for (int begin = 1; begin <= end; begin++) { 23 | if (cmp(max, begin) < 0) { 24 | max = begin; 25 | } 26 | } 27 | swap(max, end);//减少交换次数 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /01-排序/src/com/tools/Times.java: -------------------------------------------------------------------------------- 1 | package com.tools; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Times { 7 | private static final SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS"); 8 | 9 | public interface Task { 10 | void execute(); 11 | } 12 | 13 | public static void test(String title, Task task) { 14 | if (task == null) return; 15 | title = (title == null) ? "" : ("【" + title + "】"); 16 | System.out.println(title); 17 | System.out.println("开始:" + fmt.format(new Date())); 18 | long begin = System.currentTimeMillis(); 19 | task.execute(); 20 | long end = System.currentTimeMillis(); 21 | System.out.println("结束:" + fmt.format(new Date())); 22 | double delta = (end - begin) / 1000.0; 23 | System.out.println("耗时:" + delta + "秒"); 24 | System.out.println("-------------------------------------"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /04-递归/src/com/recursion/Times.java: -------------------------------------------------------------------------------- 1 | package com.recursion; 2 | import java.text.SimpleDateFormat; 3 | import java.util.Date; 4 | 5 | public class Times { 6 | private static final SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS"); 7 | 8 | public interface Task { 9 | void execute(); 10 | } 11 | 12 | public static void test(String title, Task task) { 13 | if (task == null) return; 14 | title = (title == null) ? "" : ("【" + title + "】"); 15 | System.out.println(title); 16 | System.out.println("开始:" + fmt.format(new Date())); 17 | long begin = System.currentTimeMillis(); 18 | task.execute(); 19 | long end = System.currentTimeMillis(); 20 | System.out.println("结束:" + fmt.format(new Date())); 21 | double delta = (end - begin) / 1000.0; 22 | System.out.println("耗时:" + delta + "秒"); 23 | System.out.println("-------------------------------------"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /11-字符串/src/com/sequence/BruteForce02.java: -------------------------------------------------------------------------------- 1 | package com.sequence; 2 | 3 | public class BruteForce02 { 4 | 5 | public static int indexOf(String text, String pattern) { 6 | if (text == null || pattern == null) 7 | return -1; 8 | if (text.length() == 0 || pattern.length() == 0) 9 | return -1; 10 | if (pattern.length() > text.length()) 11 | return -1; 12 | 13 | char[] textChars = text.toCharArray(); 14 | char[] patternChars = pattern.toCharArray(); 15 | int tlen = textChars.length; 16 | int plen = patternChars.length; 17 | // 使用ti表达对比字符串的起始位置 ,则ti + pi代表当前对比的index 18 | int tiMax = tlen - plen; 19 | for (int ti = 0; ti <= tiMax; ti++) { 20 | int pi = 0;//便于for循环以后使用 21 | for (; pi < plen; pi++) { 22 | if (textChars[ti + pi] != patternChars[pi]) 23 | break; 24 | } 25 | if (pi == plen) 26 | return ti; 27 | } 28 | return -1; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **题目来源:** LeetCode 4 | 5 | **运行环境:** Java 6 | 7 | **软件环境:** VSCode 8 | 9 | **初衷:** 10 | - 记录自己的解题过程和遇到的问题,巩固相关知识,完善知识体系 11 | - 正如仓库名称的后缀 **365Days**,敦促自己,争取做到每日一道 12 | - 结交到兴趣相投的朋友 13 | 14 | **目标:** 按照LeetCode提供[数据结构](https://leetcode-cn.com/explore/learn/)的学习顺序,完成数据结构和算法中简单以及中等难度的题目 15 | 16 | ![](https://github.com/CrabMen/DataStructureAndAlgorithms-365Days/blob/master/Images/desc.png) 17 | 18 | 19 | **Tips:** 20 | - 有更好的解题思路或者是代码中有错误的话,欢迎提**contribution**或者[issue](https://github.com/CrabMen/DataStructureAndAlgorithms-365Days/issues) 21 | - 如果该仓库对您哪怕有一奈奈的帮助,欢迎**⭐️star** 22 | 23 | **最后:** 最近看了一部电视剧《我是余欢水》,结局里面一段话不错,送给你们 24 | 25 | > 我曾无数次想要离开这座城市 26 | > 27 | > 离开这里的喧嚣 28 | > 29 | > 离开这里的拥堵 雾霾 还有虚伪 30 | > 31 | > 当我真的要告别他的时候 32 | > 33 | > 我只能把每天 34 | > 35 | > 当成最后一天来活 36 | > 37 | > 如果没有明天 38 | > 39 | > 一切似乎简单了不少 40 | > 41 | > 人所有的痛苦 纠结 42 | > 43 | > 就是因为还有无数个明天 44 | > 45 | > ----《我是余欢水》 46 | -------------------------------------------------------------------------------- /Top/07-DFS/_113_路径总和II.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 3 | 4 | 说明: 叶子节点是指没有子节点的节点。 5 | 6 | 示例: 7 | 给定如下二叉树,以及目标和 sum = 22, 8 | 9 | 5 10 | / \ 11 | 4 8 12 | / / \ 13 | 11 13 4 14 | / \ / \ 15 | 7 2 5 1 16 | 返回: 17 | 18 | [ 19 | [5,4,11,2], 20 | [5,8,4,5] 21 | ] 22 | 通过次数55,281提交次数92,091 23 | 24 | 来源:力扣(LeetCode) 25 | 链接:https://leetcode-cn.com/problems/path-sum-ii 26 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * 28 | * 29 | * 30 | * 31 | * 32 | */ 33 | 34 | 35 | 36 | /** 37 | * Definition for a binary tree node. 38 | * public class TreeNode { 39 | * int val; 40 | * TreeNode left; 41 | * TreeNode right; 42 | * TreeNode(int x) { val = x; } 43 | * } 44 | */ 45 | class Solution { 46 | public List> pathSum(TreeNode root, int sum) { 47 | 48 | } 49 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题21_调整数组顺序使奇数位于偶数前面.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。 3 | * 4 | * 示例: 5 | * 6 | * 输入:nums = [1,2,3,4] 输出:[1,3,2,4] 注:[3,1,2,4] 也是正确的答案之一。   7 | * 8 | * 提示: 9 | * 10 | * 1 <= nums.length <= 50000 1 <= nums[i] <= 10000 11 | * 12 | * 来源:力扣(LeetCode) 13 | * 链接:https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof 14 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 15 | * 16 | */ 17 | class Solution { 18 | public int[] exchange(int[] nums) { 19 | 20 | int i = 0, j = nums.length - 1; 21 | while (i < j) { 22 | while (i < j && (nums[i] & 1) == 1) 23 | i++; 24 | while (i < j && (nums[j] & 1) == 0) 25 | j--; 26 | int temp = nums[i]; 27 | nums[i] = nums[j]; 28 | nums[j] = temp; 29 | } 30 | return nums; 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /08-动态规划/src/com/dp/MaxSubArray.java: -------------------------------------------------------------------------------- 1 | public class MaxSubArray { 2 | public static void main(String[] args) { 3 | System.out.println(maxSubArray2(new int[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 })); 4 | } 5 | 6 | static int maxSubArray1(int[] nums) { 7 | if (nums == null || nums.length == 0) 8 | return 0; 9 | int[] dp = new int[nums.length]; 10 | dp[0] = nums[0]; 11 | int max = dp[0]; 12 | for (int i = 1; i < nums.length; i++) { 13 | dp[i] = dp[i - 1] > 0 ? dp[i - 1] + nums[i] : nums[i]; 14 | max = Math.max(max, dp[i]); 15 | } 16 | return max; 17 | } 18 | //中间值计算值没有用,使用一个变量代替数组 19 | static int maxSubArray2(int[] nums) { 20 | if (nums == null || nums.length == 0) 21 | return 0; 22 | int dp = nums[0], max = nums[0]; 23 | for (int i = 1; i < nums.length; i++) { 24 | dp = dp > 0 ? dp + nums[i] : nums[i]; 25 | max = Math.max(max, dp); 26 | } 27 | return max; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /程序员面试金典/_面试题0811_硬币.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 面试题 08.11. 硬币 4 | * 硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007) 5 | * 6 | * 示例1: 7 | * 8 | * 输入: n = 5 输出:2 9 | * 10 | * 解释: 有两种方式可以凑成总金额: 5=5 5=1+1+1+1+1 示例2: 11 | * 12 | * 输入: n = 10 输出:4 13 | * 14 | * 解释: 有四种方式可以凑成总金额: 10=10 10=5+5 10=5+1+1+1+1+1 10=1+1+1+1+1+1+1+1+1+1 说明: 15 | * 16 | * 注意: 17 | * 18 | * 你可以假设: 19 | * 20 | * 0 <= n (总金额) <= 1000000 21 | * 22 | * 通过次数16,834提交次数32,983 23 | * 24 | * 25 | * 26 | */ 27 | 28 | class Solution { 29 | public int waysToChange(int n) { 30 | int[] dp = new int[n + 1]; 31 | int[] coins = { 1, 5, 10, 25 }; 32 | dp[0] = 1; 33 | for (int coin : coins) { 34 | for (int i = 1; i <= n; i++) { 35 | if (i >= coin) 36 | dp[i] = (dp[i] + dp[i - coin]) %1000000007; 37 | } 38 | } 39 | return dp[n] ; 40 | } 41 | } -------------------------------------------------------------------------------- /Top/02-链表/_237_删除链表中的节点.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。 3 | * 4 | * 现有一个链表 -- head = [4,5,1,9],它可以表示为: 5 | * 6 | * 7 | * 8 | *   9 | * 10 | * 示例 1: 11 | * 12 | * 输入: head = [4,5,1,9], node = 5 输出: [4,1,9] 解释: 13 | * 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 示例 2: 14 | * 15 | * 输入: head = [4,5,1,9], node = 1 输出: [4,5,9] 解释: 16 | * 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9. 17 | * 18 | * 来源:力扣(LeetCode) 19 | * 链接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list 20 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 21 | * 22 | * 23 | * 24 | * 25 | */ 26 | // Definition for singly-linked list. 27 | public class ListNode { 28 | int val; 29 | ListNode next; 30 | 31 | ListNode(int x) { 32 | val = x; 33 | } 34 | } 35 | class Solution { 36 | public void deleteNode(ListNode node) { 37 | node.val = node.next.val; 38 | node.next = node.next.next; 39 | } 40 | } -------------------------------------------------------------------------------- /01-排序/src/Main.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.Arrays; 3 | 4 | import com.sort.Sort; 5 | import com.tools.Asserts; 6 | import com.tools.Integers; 7 | import com.sort.cmp.BubbleSort1; 8 | import com.sort.cmp.BubbleSort2; 9 | import com.sort.cmp.BubbleSort3; 10 | import com.sort.cmp.SelectionSort; 11 | 12 | public class Main { 13 | public static void main(String[] args) { 14 | Integer[] array = { 7, 3, 5, 8, 6, 7, 4, 5, 10, 12, 13 }; 15 | testSorts(array, new BubbleSort1<>(), new BubbleSort2<>(), new BubbleSort3<>(), new SelectionSort<>()); 16 | } 17 | 18 | static void testSorts(Integer[] array, Sort... sorts) { 19 | for (Sort sort : sorts) { 20 | Integer[] newArray = Integers.copy(array); 21 | sort.sort(newArray); 22 | Asserts.test(Integers.isAscOrder(newArray)); 23 | } 24 | Arrays.sort(sorts); 25 | 26 | System.out.println("------------------------------------------------------------------"); 27 | 28 | for (Sort sort : sorts) { 29 | System.out.println(sort); 30 | } 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题63_股票的最大利润.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 面试题63. 股票的最大利润 假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少? 3 | * 4 | * 5 | * 6 | * 示例 1: 7 | * 8 | * 输入: [7,1,5,3,6,4] 9 | * 10 | * 输出: 5 11 | * 12 | * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 13 | * = 6, 因为卖出价格需要大于买入价格。 14 | * 15 | * 16 | * 17 | * 示例 2: 18 | * 19 | * 输入: [7,6,4,3,1] 20 | * 21 | * 输出: 0 22 | * 23 | * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 24 | * 25 | * 26 | * 限制: 27 | * 28 | * 0 <= 数组长度 <= 10^5 29 | * 30 | * 31 | * 32 | * 注意:本题与主站 121 33 | * 题相同:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/ 34 | * 35 | * 36 | * 37 | */ 38 | 39 | class Solution { 40 | 41 | public int maxProfit(int[] prices) { 42 | int minPrice = Integer.MAX_VALUE, profit = 0; 43 | for (int price : prices) { 44 | minPrice = Math.min(minPrice, price); 45 | profit = Math.max(profit, price - minPrice); 46 | } 47 | return profit; 48 | } 49 | } -------------------------------------------------------------------------------- /Top/01-数组/_88_合并两个有序数组.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。 3 | * 4 | * 5 | * 说明: 6 | * 7 | * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 8 | * nums2 中的元素。   9 | * 10 | * 示例: 11 | * 12 | * 输入: nums1 = [1,2,3,0,0,0], m = 3 nums2 = [2,5,6], n = 3 13 | * 14 | * 输出: [1,2,2,3,5,6] 15 | * 16 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/merge-sorted-array 17 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 18 | * 19 | * 20 | */ 21 | 22 | /** 23 | * 24 | * 25 | * 题目分析: 数组类似的排序的问题基本都可以通过双指针或者是三指针解决 26 | * 十大排序中归并排序的思想 27 | */ 28 | class Solution { 29 | public void merge(int[] nums1, int m, int[] nums2, int n) { 30 | int idx1 = m - 1, idx2 = n - 1, cur = nums1.length - 1; 31 | while (idx2 >= 0) { 32 | if (idx1 >= 0 && nums1[idx1] > nums2[idx2]) { 33 | nums1[cur--] = nums1[idx1--]; 34 | } else { 35 | nums1[cur--] = nums2[idx2--]; 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题22_链表中倒数第k个节点.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 4 | * 输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。 5 | * 6 | *   7 | * 8 | * 示例: 9 | * 10 | * 给定一个链表: 1->2->3->4->5, 和 k = 2. 11 | * 12 | * 返回链表 4->5. 13 | * 14 | * 来源:力扣(LeetCode) 15 | * 链接:https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof 16 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 17 | * 18 | * 19 | * 20 | */ 21 | 22 | // Definition for singly-linked list. 23 | public class ListNode { 24 | int val; 25 | ListNode next; 26 | 27 | ListNode(int x) { 28 | val = x; 29 | } 30 | } 31 | 32 | class Solution { 33 | public ListNode getKthFromEnd(ListNode head, int k) { 34 | ListNode fast = head, slow = head; 35 | int i = 0; 36 | while (fast != null) { 37 | if (i >= k) 38 | slow = slow.next; 39 | fast = fast.next; 40 | i++; 41 | } 42 | return slow; 43 | 44 | } 45 | } -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_556. 下一个更大元素 III.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 给定一个32位正整数 n,你需要找到最小的32位整数,其与 n 中存在的位数完全相同,并且其值大于n。如果不存在这样的32位整数,则返回-1。 4 | * 5 | * 示例 1: 6 | * 7 | * 输入: 12 输出: 21 8 | * 9 | * 示例 2: 10 | * 11 | * 输入: 21 输出: -1 12 | * 13 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/next-greater-element-iii 14 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 15 | */ 16 | /** 17 | * 官方采用的是非Stack&Queue相关题目 但是官网却将该题放在相似题目内,于是想采用栈解决,评论区大老 18 | * 19 | * 20 | * 1.从个位数开始往高位数遍历,如果每个高位数都大于相邻的低位数,则此数字已经是最大的了,直接返回-1。 21 | * 2.否则遍历直到发现首次出现高位数比相邻的低位数小的情况(称这个高位数所在的位为“分界点”),这时应该在分界点右边的所有数里面找出最小的比它大的数,把两个数交换位置,此时“分界点”右边的数仍然是从大到小,两两交换使它们顺序改为从小到大,然后转换成int返回。 22 | * 23 | * 代码 24 | * 25 | * 作者:ben-da-xiong 26 | * 链接:https://leetcode-cn.com/problems/next-greater-element-iii/solution/javajie-fa-0msji-bai-100-by-ben-da-xiong/ 27 | * 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 28 | * 29 | */ 30 | 31 | class Solution { 32 | public int nextGreaterElement(int n) { 33 | String string = String.valueOf(n); 34 | 35 | } 36 | } -------------------------------------------------------------------------------- /Top/02-链表/_203_移除链表元素.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 删除链表中等于给定值 val 的所有节点。 3 | * 4 | * 示例: 5 | * 6 | * 输入: 1->2->6->3->4->5->6, val = 6 输出: 1->2->3->4->5 7 | * 8 | */ 9 | 10 | // Definition for singly-linked list. 11 | public class ListNode { 12 | int val; 13 | ListNode next; 14 | 15 | ListNode(int x) { 16 | val = x; 17 | } 18 | } 19 | 20 | class Solution { 21 | public ListNode removeElements(ListNode head, int val) { 22 | 23 | if (head == null) 24 | return null; 25 | // 新链表的头结点和尾结点,使用虚拟头结点进行优化 26 | ListNode newHead = new ListNode(0), newTail = newHead; 27 | while (head != null) { 28 | 29 | if (head.val != val) { 30 | // 保证当前链表连贯性以后,并重新挪动newTail位置 31 | // newTail.next = head; 32 | // newTail = head; 33 | newTail = newTail.next = head; 34 | } 35 | head = head.next; 36 | } 37 | // 重新给尾节点指向 38 | newTail.next = null; 39 | return newHead.next; 40 | } 41 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题10_I_斐波那契数列.java: -------------------------------------------------------------------------------- 1 | import sun.management.Sensor; 2 | 3 | /** 4 | * 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下: 5 | * 6 | * F(0) = 0,   F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 斐波那契数列由 0 和 1 7 | * 开始,之后的斐波那契数就是由之前的两数相加而得出。 8 | * 9 | * 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 10 | * 11 | *   12 | * 13 | * 示例 1: 14 | * 15 | * 输入:n = 2 输出:1 示例 2: 16 | * 17 | * 输入:n = 5 输出:5   18 | * 19 | * 提示: 20 | * 21 | * 0 <= n <= 100 注意:本题与主站 509 22 | * 题相同:https://leetcode-cn.com/problems/fibonacci-number/ 23 | * 24 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof 25 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 26 | * 27 | * 28 | * 29 | */ 30 | 31 | class Solution { 32 | public int fib(int n) { 33 | 34 | int first = 0, second = 1, sum = 0; 35 | for (int i = 0; i < n; i++) { 36 | sum = (first + second)%1000000007; 37 | first = second; 38 | second = sum; 39 | } 40 | return first; 41 | } 42 | } -------------------------------------------------------------------------------- /Top/02-链表/_21_合并两个有序链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。  3 | * 4 | *   5 | * 6 | * 示例: 7 | * 8 | * 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 9 | * 10 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/merge-two-sorted-lists 11 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 12 | */ 13 | 14 | // Definition for singly-linked list. 15 | public class ListNode { 16 | int val; 17 | ListNode next; 18 | 19 | ListNode(int x) { 20 | val = x; 21 | } 22 | } 23 | 24 | class Solution { 25 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 26 | ListNode prehead = new ListNode(-1); 27 | ListNode prev = prehead; 28 | while (l1 != null && l2 != null) { 29 | if (l1.val <= l2.val) { 30 | prev.next = l1; 31 | l1 = l1.next; 32 | } else { 33 | prev.next = l2; 34 | l2 = l2.next; 35 | } 36 | prev = prev.next; 37 | } 38 | prev.next = l1 == null ? l2 : l1; 39 | return prehead.next; 40 | } 41 | } -------------------------------------------------------------------------------- /Leetcode/Array&String/_28_实现strStr().java: -------------------------------------------------------------------------------- 1 | /** 2 | * 实现 strStr() 函数。 3 | * 4 | * 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 5 | * (从0开始)。如果不存在,则返回  -1。 6 | * 7 | * 示例 1: 8 | * 9 | * 输入: haystack = "hello", needle = "ll" 输出: 2 10 | * 11 | * 12 | * 示例 2: 13 | * 14 | * 输入: haystack = "aaaaa", needle = "bba" 输出: -1 15 | * 16 | * 17 | * 说明: 18 | * 19 | * 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 20 | * 21 | * 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 22 | * 23 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/implement-strstr 24 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 25 | * 26 | * 27 | * 28 | */ 29 | 30 | 31 | /** 32 | * 33 | * 官方题解 34 | * 35 | * 后期可以尝试使用双指针再解一下 36 | */ 37 | 38 | class Solution { 39 | public int strStr(String haystack, String needle) { 40 | int L = haystack.length(), l = needle.length(); 41 | for (int i = 0; i <= L - l; i++) { 42 | if (haystack.substring(i, i + l).equals(needle)) 43 | return i; 44 | } 45 | return -1; 46 | } 47 | } -------------------------------------------------------------------------------- /Leetcode/Array&String/_66.加一.java: -------------------------------------------------------------------------------- 1 | import jdk.nashorn.api.tree.ForInLoopTree; 2 | 3 | /** 4 | * 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 5 | * 6 | * 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 7 | * 8 | * 你可以假设除了整数 0 之外,这个整数不会以零开头。 9 | * 10 | * 示例 1: 11 | * 12 | * 输入: [1,2,3] 输出: [1,2,4] 解释: 输入数组表示数字 123。 13 | * 14 | * 示例 2: 15 | * 16 | * 输入: [4,3,2,1] 输出: [4,3,2,2] 解释: 输入数组表示数字 4321。 17 | * 18 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/plus-one 19 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 20 | * 21 | * 22 | */ 23 | 24 | /** 25 | * 执行用时 : 0 ms , 在所有 Java 提交中击败了 100.00% 的用户 26 | * 27 | * 内存消耗 : 38.4 MB , 在所有 Java 提交中击败了5.63% 28 | * 29 | */ 30 | class Solution { 31 | public int[] plusOne(int[] digits) { 32 | for (int i = digits.length - 1; i >= 0; i--) { 33 | digits[i] = ++digits[i]; 34 | if (digits[i] != 10) 35 | return digits; 36 | else 37 | digits[i] = 0; 38 | } 39 | digits = new int[digits.length + 1]; 40 | digits[0] = 1; 41 | return digits; 42 | } 43 | } 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_739. 每日温度.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | /** 4 | * 根据每日 气温 列表,请重新生成一个列表,对应位置的输出是需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。 5 | * 6 | * 例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 7 | * 2, 1, 1, 0, 0]。 8 | * 9 | * 提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。 10 | * 11 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/daily-temperatures 12 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 13 | * 14 | */ 15 | class Solution { 16 | public int[] dailyTemperatures(int[] T) { 17 | 18 | if (T.length == 0) return T; 19 | 20 | Stack stack = new Stack<>(); 21 | int[] result = new int[T.length]; 22 | for (int i = 0; i < result.length; i++) { 23 | result[i] = 0; 24 | } 25 | for (int i = 0; i < T.length; i++) { 26 | while (!stack.isEmpty() && T[i] > T[stack.peek()] ) { 27 | int idx = stack.pop(); 28 | result[idx] = i - idx; 29 | } 30 | stack.push(i); 31 | } 32 | return result; 33 | } 34 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题14_I_剪绳子.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 4 | * 。请问 k[0]*k[1]*...*k[m-1] 5 | * 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。 6 | * 7 | * 示例 1: 8 | * 9 | * 输入: 2 输出: 1 解释: 2 = 1 + 1, 1 × 1 = 1 10 | * 11 | * 12 | * 示例 2: 13 | * 14 | * 输入: 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36 15 | * 16 | * 17 | * 提示: 18 | * 19 | * 2 <= n <= 58 注意:本题与主站 343 题相同:https://leetcode-cn.com/problems/integer-break/ 20 | * 21 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof 22 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 23 | * 24 | * 25 | */ 26 | 27 | class Solution { 28 | public int cuttingRope(int n) { 29 | int[] dp = new int[n + 1]; 30 | dp[2] = 1; 31 | //dp[n] 代表剪了n次以后乘积最大 32 | for (int i = 3; i <= n; i++) { 33 | for (int j = 1; j < i; j++) { 34 | //j代表减多少次 ; dp[j](第j次就不减了) 35 | dp[i] = Math.max(dp[j], Math.max((i - j) * j, dp[i - j] * j)); 36 | } 37 | } 38 | return dp[n]; 39 | 40 | } 41 | } -------------------------------------------------------------------------------- /Top/05-动态规划/_面试题47_礼物的最大价值.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物? 4 | 5 |   6 | 7 | 示例 1: 8 | 9 | 输入: 10 | [ 11 |   [1,3,1], 12 |   [1,5,1], 13 |   [4,2,1] 14 | ] 15 | 输出: 12 16 | 解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物 17 |   18 | 19 | 提示: 20 | 21 | 0 < grid.length <= 200 22 | 0 < grid[0].length <= 200 23 | 24 | 来源:力扣(LeetCode) 25 | 链接:https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof 26 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * 28 | * 29 | * 30 | * 31 | */ 32 | 33 | /** 34 | * 动态规划典型 35 | */ 36 | class Solution { 37 | public int maxValue(int[][] grid) { 38 | if (grid == null) 39 | return 0; 40 | 41 | int rc = grid.length; 42 | int cc = grid[0].length; 43 | int[][] dp = new int[rc + 1][cc + 1]; 44 | 45 | for (int i = 1; i <= rc; i++) { 46 | for (int j = 1; j <= cc; j++) { 47 | dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1]; 48 | } 49 | } 50 | return dp[rc][cc]; 51 | } 52 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 CrabMan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /剑指Offer/_面试题25_合并两个排序的链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。 3 | * 4 | * 示例1: 5 | * 6 | * 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 限制: 7 | * 8 | * 0 <= 链表长度 <= 1000 9 | * 10 | * 来源:力扣(LeetCode) 11 | * 链接:https://leetcode-cn.com/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof 12 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 13 | * 14 | */ 15 | 16 | // Definition for singly-linked list. 17 | public class ListNode { 18 | int val; 19 | ListNode next; 20 | 21 | ListNode(int x) { 22 | val = x; 23 | } 24 | } 25 | 26 | class Solution { 27 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 28 | 29 | ListNode head = new ListNode(0); 30 | ListNode cur = head; 31 | 32 | while (l1 != null && l2 != null) { 33 | if (l2.val > l1.val) { 34 | cur.next = l1; 35 | l1 = l1.next; 36 | } else { 37 | cur.next = l2; 38 | l2 = l2.next; 39 | } 40 | cur = cur.next; 41 | } 42 | cur.next = l1 == null ? l2 : l1; 43 | return head.next; 44 | } 45 | } -------------------------------------------------------------------------------- /Top/03-栈&队列/面试题_09_用两个栈实现队列.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * 用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead 5 | * ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 ) 6 | * 7 | *   8 | * 9 | * 示例 1: 10 | * 11 | * 输入: ["CQueue","appendTail","deleteHead","deleteHead"] [[],[3],[],[]] 12 | * 输出:[null,null,3,-1] 示例 2: 13 | * 14 | * 输入: 15 | * ["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"] 16 | * [[],[],[5],[2],[],[]] 输出:[null,-1,null,null,5,2] 提示: 17 | * 18 | * 1 <= values <= 10000 最多会对 appendTail、deleteHead 进行 10000 次调用 19 | * 20 | * 来源:力扣(LeetCode) 21 | * 链接:https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof 22 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 23 | * 24 | * 25 | */ 26 | 27 | class CQueue { 28 | 29 | public CQueue() { 30 | 31 | } 32 | 33 | public void appendTail(int value) { 34 | 35 | } 36 | 37 | public int deleteHead() { 38 | 39 | } 40 | } 41 | 42 | /** 43 | * Your CQueue object will be instantiated and called as such: 44 | * CQueue obj = new CQueue(); 45 | * obj.appendTail(value); 46 | * int param_2 = obj.deleteHead(); 47 | */ -------------------------------------------------------------------------------- /Leetcode/Array&String/_118.杨辉三角.java: -------------------------------------------------------------------------------- 1 | import java.lang.reflect.Array; 2 | import java.util.ArrayList; 3 | 4 | import list.List; 5 | 6 | /** 7 | * 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。 8 | * 9 | * 在杨辉三角中,每个数是它左上方和右上方的数的和。 10 | * 11 | * 示例: 12 | * 13 | * 输入: 5 输出: [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] 14 | * 15 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/pascals-triangle 16 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 17 | * 18 | */ 19 | 20 | class Solution { 21 | public List> generate(int numRows) { 22 | List> result = new ArrayList<>(); 23 | int r = 0, c = 0; 24 | for (int i = 0; i < numRows; i++) { 25 | List row = new ArrayList<>(); 26 | for (int j = 0; j <= i; j++) { 27 | if (i > 0 && j > 0 && j< i) { 28 | Integer num = result.get(i - 1).get(j) + result.get(i - 1).get(j - 1); 29 | row.add(num); 30 | } else { 31 | row.add(1); 32 | } 33 | } 34 | result.add(row); 35 | } 36 | return result; 37 | } 38 | } -------------------------------------------------------------------------------- /Top/04-字符串/_242_有效的字母异位词.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 3 | * 4 | * 示例 1: 5 | * 6 | * 输入: s = "anagram", t = "nagaram" 输出: true 示例 2: 7 | * 8 | * 输入: s = "rat", t = "car" 输出: false 说明: 你可以假设字符串只包含小写字母。 9 | * 10 | * 进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况? 11 | * 12 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/valid-anagram 13 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 14 | * 15 | * 16 | * 17 | */ 18 | // 字母异位词 每个字母出现的次数一致 19 | class Solution { 20 | public boolean isAnagram(String s, String t) { 21 | if (s == null || t == null) 22 | return false; 23 | 24 | char[] schars = s.toCharArray(); 25 | char[] tchars = t.toCharArray(); 26 | 27 | if (schars.length != tchars.length) 28 | return false; 29 | 30 | int[] counts = new int[26]; 31 | 32 | for (int i = 0; i < schars.length; i++) { 33 | counts[schars[i] - 'a']++; 34 | } 35 | 36 | for (int i = 0; i < tchars.length; i++) { 37 | if (--counts[tchars[i] - 'a'] < 0) 38 | return false; 39 | } 40 | 41 | return true; 42 | } 43 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题46_把数字翻译成字符串.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 3 | * “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。 4 | * 5 | *   6 | * 7 | * 示例 1: 8 | * 9 | * 输入: 12258 输出: 5 解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"   10 | * 11 | * 提示: 12 | * 13 | * 0 <= num < 231 14 | * 15 | * 来源:力扣(LeetCode) 16 | * 链接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof 17 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 18 | * 19 | * 20 | */ 21 | 22 | class Solution { 23 | public int translateNum(int num) { 24 | return translateNum(num); 25 | } 26 | 27 | static int translateNum_dp(int num) { 28 | String s = String.valueOf(num); 29 | int[] dp = new int[s.length() + 1]; 30 | dp[0] = dp[1] = 1; 31 | for (int i = 2; i <= s.length(); i++) { 32 | String temp = s.substring(i - 2, i); 33 | if (temp.compareTo("10") >= 0 && temp.compareTo("25") <= 0) 34 | dp[i] = dp[i - 1] + dp[i - 2]; 35 | else 36 | dp[i] = dp[i - 1]; 37 | } 38 | return dp[s.length()]; 39 | } 40 | } -------------------------------------------------------------------------------- /00.数据结构/src/list/AbstractList.java: -------------------------------------------------------------------------------- 1 | package list; 2 | 3 | public abstract class AbstractList implements List { 4 | /** 5 | * 元素的数量 6 | */ 7 | protected int size; 8 | /** 9 | * 元素的数量 10 | * @return 11 | */ 12 | public int size() { 13 | return size; 14 | } 15 | 16 | /** 17 | * 是否为空 18 | * @return 19 | */ 20 | public boolean isEmpty() { 21 | return size == 0; 22 | } 23 | 24 | /** 25 | * 是否包含某个元素 26 | * @param element 27 | * @return 28 | */ 29 | public boolean contains(E element) { 30 | return indexOf(element) != ELEMENT_NOT_FOUND; 31 | } 32 | 33 | /** 34 | * 添加元素到尾部 35 | * @param element 36 | */ 37 | public void add(E element) { 38 | add(size, element); 39 | } 40 | 41 | protected void outOfBounds(int index) { 42 | throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size); 43 | } 44 | 45 | protected void rangeCheck(int index) { 46 | if (index < 0 || index >= size) { 47 | outOfBounds(index); 48 | } 49 | } 50 | 51 | protected void rangeCheckForAdd(int index) { 52 | if (index < 0 || index > size) { 53 | outOfBounds(index); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Top/08-高频题/_1_两数之和.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | import java.util.Map; 3 | 4 | /** 5 | * 6 | * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 7 | * 8 | * 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 9 | * 10 | *   11 | * 12 | * 示例: 13 | * 14 | * 给定 nums = [2, 7, 11, 15], target = 9 15 | * 16 | * 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 17 | * 18 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/two-sum 19 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 20 | * 21 | * 22 | * 23 | */ 24 | 25 | class Solution { 26 | public int[] twoSum(int[] nums, int target) { 27 | /** 28 | * 暴力法 枚举枚举每一对整数 时间复杂度O(n^2) 空间复杂度时间复杂度O(1) 29 | * 30 | * 是否能使用 31 | * 32 | * O(n) 空间复杂度 时间复杂度O(n)实现呢? 33 | * 34 | */ 35 | 36 | if (nums == null) 37 | return null; 38 | Map map = new HashMap(); 39 | for (int i = 0; i < nums.length; i++) { 40 | Integer idx = map.get(target - nums[i]); 41 | if (idx != null) 42 | return new int[] { idx, i }; 43 | map.put(nums[i], i); 44 | } 45 | return null; 46 | 47 | } 48 | } -------------------------------------------------------------------------------- /00.数据结构/src/list/List.java: -------------------------------------------------------------------------------- 1 | package list; 2 | 3 | public interface List { 4 | static final int ELEMENT_NOT_FOUND = -1; 5 | /** 6 | * 清除所有元素 7 | */ 8 | void clear(); 9 | 10 | /** 11 | * 元素的数量 12 | * @return 13 | */ 14 | int size(); 15 | 16 | /** 17 | * 是否为空 18 | * @return 19 | */ 20 | boolean isEmpty(); 21 | 22 | /** 23 | * 是否包含某个元素 24 | * @param element 25 | * @return 26 | */ 27 | boolean contains(E element); 28 | 29 | /** 30 | * 添加元素到尾部 31 | * @param element 32 | */ 33 | void add(E element); 34 | 35 | /** 36 | * 获取index位置的元素 37 | * @param index 38 | * @return 39 | */ 40 | E get(int index); 41 | 42 | /** 43 | * 设置index位置的元素 44 | * @param index 45 | * @param element 46 | * @return 原来的元素ֵ 47 | */ 48 | E set(int index, E element); 49 | 50 | /** 51 | * 在index位置插入一个元素 52 | * @param index 53 | * @param element 54 | */ 55 | void add(int index, E element); 56 | 57 | /** 58 | * 删除index位置的元素 59 | * @param index 60 | * @return 61 | */ 62 | E remove(int index); 63 | 64 | /** 65 | * 查看元素的索引 66 | * @param element 67 | * @return 68 | */ 69 | int indexOf(E element); 70 | } 71 | -------------------------------------------------------------------------------- /剑指Offer/_面试题57_和为s的两个数字.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 4 | * 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s 5 | * 6 | * 。如果有多对数字的和等于s,则输出任意一对即可。 7 | * 8 | */ 9 | 10 | class Solution { 11 | public int[] twoSum(int[] nums, int target) { 12 | if (nums == null || target < 3) 13 | return new int[0]; 14 | return twoSum_doublePointer(nums, target); 15 | } 16 | 17 | static int[] twoSum_doublePointer(int[] nums, int target) { 18 | int i = 0, j = nums.length - 1; 19 | while (i < j) { 20 | int sum = nums[i] + nums[j]; 21 | if (sum > target) 22 | j--; 23 | else if (sum < target) 24 | i++; 25 | else 26 | return new int[] { nums[i], nums[j] }; 27 | } 28 | return new int[0]; 29 | } 30 | 31 | static int[] twoSum_map(int[] nums, int target) { 32 | Map map = new HashMap<>(); 33 | for (int i = 0; i < nums.length; i++) { 34 | int result = target - nums[i]; 35 | if (map.containsKey(result)) 36 | return new int[] { result, nums[i] }; 37 | map.put(nums[i], i); 38 | } 39 | return new int[0]; 40 | } 41 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题18_删除链表的节点.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。 3 | * 4 | * 返回删除后的链表的头节点。 5 | * 6 | * 注意:此题对比原题有改动 7 | * 8 | * 示例 1: 9 | * 10 | * 输入: head = [4,5,1,9], val = 5 输出: [4,1,9] 解释: 11 | * 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 示例 2: 12 | * 13 | * 输入: head = [4,5,1,9], val = 1 输出: [4,5,9] 解释: 14 | * 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.   15 | * 16 | * 说明: 17 | * 18 | * 题目保证链表中节点的值互不相同 若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点 19 | * 20 | * 来源:力扣(LeetCode) 21 | * 链接:https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof 22 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 23 | * 24 | * 25 | * 26 | */ 27 | // Definition for singly-linked list. 28 | public class ListNode { 29 | int val; 30 | ListNode next; 31 | 32 | ListNode(int x) { 33 | val = x; 34 | } 35 | } 36 | 37 | class Solution { 38 | public ListNode deleteNode(ListNode head, int val) { 39 | if (head == null) 40 | return null; 41 | if (head.val == val) 42 | return head.next; 43 | ListNode cur = head; 44 | while (cur.next.val != val) 45 | cur = cur.next; 46 | cur.next = cur.next.next; 47 | return head; 48 | } 49 | } -------------------------------------------------------------------------------- /11-字符串/src/com/tools/Times.java: -------------------------------------------------------------------------------- 1 | package com.tools; 2 | 3 | public class Times { 4 | public interface Task { 5 | void execute(); 6 | } 7 | 8 | public interface ReturnTask { 9 | Object execute(); 10 | } 11 | 12 | public static void test(String title, Task task) { 13 | if (task == null) return; 14 | printTitle(title); 15 | 16 | long begin = System.currentTimeMillis(); 17 | task.execute(); 18 | long end = System.currentTimeMillis(); 19 | 20 | printDuration(begin, end); 21 | } 22 | 23 | public static Object test(String title, ReturnTask task) { 24 | if (task == null) return null; 25 | printTitle(title); 26 | 27 | long begin = System.currentTimeMillis(); 28 | Object result = task.execute(); 29 | long end = System.currentTimeMillis(); 30 | 31 | printDuration(begin, end); 32 | return result; 33 | } 34 | 35 | private static void printTitle(String title) { 36 | title = (title == null) ? "" : ("【" + title + "】"); 37 | System.out.println(title); 38 | } 39 | 40 | private static void printDuration(long begin, long end) { 41 | double duration = end - begin; 42 | System.out.println("耗时:" + duration / 1000.0 + "s(" + duration + "ms)"); 43 | System.out.println("-------------------------------------"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /剑指Offer/_面试题61_扑克牌中的顺子.java: -------------------------------------------------------------------------------- 1 | import java.util.HashSet; 2 | import java.util.Set; 3 | 4 | /** 5 | * 6 | * 从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 7 | * ,可以看成任意数字。A 不能视为 14。 8 | * 9 | * 示例 1: 10 | * 11 | * 输入: [1,2,3,4,5] 输出: True   12 | * 13 | * 示例 2: 14 | * 15 | * 输入: [0,0,1,2,5] 输出: True   16 | * 17 | * 限制: 18 | * 19 | * 数组长度为 5  20 | * 21 | * 数组的数取值为 [0, 13] . 22 | * 23 | * 来源:力扣(LeetCode) 24 | * 链接:https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof 25 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 26 | * 27 | * 28 | */ 29 | 30 | // 作者:jyd 31 | // 链接:https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof/solution/mian-shi-ti-61-bu-ke-pai-zhong-de-shun-zi-ji-he-se/ 32 | // 来源:力扣(LeetCode) 33 | // 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 34 | class Solution { 35 | public boolean isStraight(int[] nums) { 36 | 37 | int min = 14, max = 0; 38 | Set repeat = new HashSet<>(); 39 | for (int num : nums) { 40 | if (num == 0) 41 | continue; 42 | max = Math.max(max, num); 43 | min = Math.min(min, num); 44 | if (repeat.contains(num)) 45 | return false; 46 | repeat.add(num); 47 | } 48 | return max - min < 5; 49 | } 50 | } -------------------------------------------------------------------------------- /Top/03-栈&队列/_20_有效的括号.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | /** 4 | * 5 | * 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 6 | * 7 | * 有效字符串需满足: 8 | * 9 | * 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。 10 | * 11 | * 示例 1: 12 | * 13 | * 输入: "()" 输出: true 示例 2: 14 | * 15 | * 输入: "()[]{}" 输出: true 16 | * 17 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/valid-parentheses 18 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 19 | * 20 | * 21 | */ 22 | 23 | class Solution { 24 | public boolean isValid(String s) { 25 | if (s == null) 26 | return false; 27 | 28 | char[] chars = s.toCharArray(); 29 | if ((chars.length & 1) > 0) 30 | return false; 31 | Stack stack = new Stack<>(); 32 | for (Character c : chars) { 33 | if (stack.isEmpty()) 34 | stack.push(c); 35 | else if (isPair(stack.peek(), c)) 36 | stack.pop(); 37 | else 38 | stack.push(c); 39 | } 40 | return stack.isEmpty(); 41 | } 42 | 43 | private boolean isPair(Character c1, Character c2) { 44 | if ((c1 == '(' && c2 == ')') || (c1 == '[' && c2 == ']') || (c1 == '{' && c2 == '}')) 45 | return true; 46 | else 47 | return false; 48 | } 49 | } -------------------------------------------------------------------------------- /Leetcode/Array&String/_747.至少是其他数字两倍的最大数.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 在一个给定的数组nums中,总是存在一个最大元素 。 3 | * 4 | * 查找数组中的最大元素是否至少是数组中每个其他数字的两倍。 5 | * 6 | * 如果是,则返回最大元素的索引,否则返回-1。 7 | * 8 | * 示例 1: 9 | * 10 | * 输入: nums = [3, 6, 1, 0] 输出: 1 解释: 6是最大的整数, 对于数组中的其他整数, 6大于数组中其他元素的两倍。6的索引是1, 11 | * 所以我们返回1.   12 | * 13 | * 示例 2: 14 | * 15 | * 输入: nums = [1, 2, 3, 4] 输出: -1 解释: 4没有超过3的两倍大, 所以我们返回 -1.   16 | * 17 | * 提示: 18 | * 19 | * nums 的长度范围在[1, 50]. 每个 nums[i] 的整数范围在 [0, 100]. 20 | * 21 | * 来源:力扣(LeetCode) 22 | * 链接:https://leetcode-cn.com/problems/largest-number-at-least-twice-of-others 23 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | * 25 | * 26 | * 27 | * 28 | */ 29 | 30 | /** 31 | * 执行结果: 通过 32 | * 33 | * 显示详情 执行用时 : 0 ms , 在所有 Java 提交中击败了 100.00% 的用户 34 | * 35 | * 内存消耗 : 37.2 MB , 在所有Java 提交中击败了 6.25% 的用户 36 | */ 37 | class Solution { 38 | public int dominantIndex(int[] nums) { 39 | int maxIdx = 0; 40 | for (int i = 1; i < nums.length; i++) { 41 | if (nums[i] > nums[maxIdx]) 42 | maxIdx = i; 43 | } 44 | 45 | for (int i = 0; i < nums.length; i++) { 46 | if (maxIdx == i) 47 | continue; 48 | if (nums[i] > nums[maxIdx] * 0.5) 49 | return -1; 50 | } 51 | return maxIdx; 52 | 53 | } 54 | } -------------------------------------------------------------------------------- /Top/02-链表/_138_复制带随机指针的链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。 4 | * 5 | * 要求返回这个链表的 深拷贝。  6 | * 7 | * 我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示: 8 | * 9 | * val:一个表示 Node.val 的整数。 10 | * random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。   11 | * 12 | * 示例 1: 13 | * 14 | * 15 | * 16 | * 输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] 17 | * 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]] 示例 2: 18 | * 19 | * 20 | * 21 | * 输入:head = [[1,1],[2,1]] 输出:[[1,1],[2,1]] 示例 3: 22 | * 23 | * 24 | * 25 | * 输入:head = [[3,null],[3,0],[3,null]] 输出:[[3,null],[3,0],[3,null]] 示例 4: 26 | * 27 | * 输入:head = [] 输出:[] 解释:给定的链表为空(空指针),因此返回 null。   28 | * 29 | * 提示: 30 | * 31 | * -10000 <= Node.val <= 10000 Node.random 为空(null)或指向链表中的节点。 节点数目不超过 1000 。 32 | * 33 | * 来源:力扣(LeetCode) 34 | * 链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer 35 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 36 | * 37 | * 38 | * 39 | */ 40 | // Definition for a Node. 41 | class Node { 42 | int val; 43 | Node next; 44 | Node random; 45 | 46 | public Node(int val) { 47 | this.val = val; 48 | this.next = null; 49 | this.random = null; 50 | } 51 | } 52 | 53 | class Solution { 54 | public Node copyRandomList(Node head) { 55 | 56 | } 57 | } -------------------------------------------------------------------------------- /Top/08-高频题/_剑指Offer62_圆圈中最后剩下的数字.java: -------------------------------------------------------------------------------- 1 | import jdk.internal.jshell.tool.resources.version; 2 | 3 | /** 4 | * 5 | * 0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。 6 | * 7 | * 例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。 8 | * 9 | *   10 | * 11 | * 示例 1: 12 | * 13 | * 输入: n = 5, m = 3 输出: 3 示例 2: 14 | * 15 | * 输入: n = 10, m = 17 输出: 2   16 | * 17 | * 限制: 18 | * 19 | * 1 <= n <= 10^5 1 <= m <= 10^6 20 | * 21 | * 来源:力扣(LeetCode) 22 | * 链接:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof 23 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | * 25 | * 26 | * 27 | * 28 | */ 29 | 30 | class Solution { 31 | public int lastRemaining(int n, int m) { 32 | return lastRemaining_notRecursion(n, m); 33 | } 34 | 35 | //将递归优化为非递归 36 | public int lastRemaining_notRecursion(int n, int m) { 37 | int result = 0; 38 | for (int i = 2; i <= n; i++) { 39 | result = (result + m) % i; 40 | } 41 | return result; 42 | } 43 | 44 | 45 | public int lastRemaining_recursion(int n, int m) { 46 | /** 47 | * 当总人数只有1时,剩下的都是索引为0的值; 48 | * 每次删除掉一个数字以后,当前数值所在的都需要从index为0时开始;最后对该数值取余,是为了保证索引值不越界 49 | */ 50 | return n == 1 ? 0 : (lastRemaining(n - 1, m) + m) % n; 51 | 52 | } 53 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题62_圆圈中最后剩下的数字.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。 3 | * 4 | * 例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。 5 | * 6 | * 来源:力扣(LeetCode) 7 | * 链接:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof 8 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 9 | * 10 | * 11 | * 示例 1: 12 | * 13 | * 输入: n = 5, m = 3 14 | * 15 | * 输出: 3 16 | * 17 | * 示例 2: 18 | * 19 | * 输入: n = 10, m = 17 输出: 2   20 | * 21 | * 限制: 22 | * 23 | * 1 <= n <= 10^5 24 | * 25 | * 1 <= m <= 10^6 26 | * 27 | * 来源:力扣(LeetCode) 28 | * 链接:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof 29 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 30 | * 31 | */ 32 | 33 | /** 34 | * Sweetiee 这么著名的约瑟夫环问题,是有数学解法的! 35 | * 36 | * 作者:sweetieeyi 37 | * 链接:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solution/javajie-jue-yue-se-fu-huan-wen-ti-gao-su-ni-wei-sh/ 38 | * 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 39 | * 40 | */ 41 | 42 | class Solution { 43 | public int lastRemaining(int n, int m) { 44 | int ans = 0; 45 | // 最后一轮剩下2个人,所以从2开始反推 46 | for (int i = 2; i <= n; i++) { 47 | ans = (ans + m) % i; 48 | } 49 | return ans; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /剑指Offer/_面试题03_数组中重复的数字.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.HashSet; 3 | import java.util.Set; 4 | 5 | /** 6 | * 找出数组中重复的数字。 7 | * 8 | * 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 9 | * 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。 10 | * 11 | * 示例 1: 12 | * 13 | * 输入: [2, 3, 1, 0, 2, 5, 3] 14 | * 15 | * 输出:2 或 3   16 | * 17 | * 限制: 18 | * 19 | * 2 <= n <= 100000 20 | * 21 | * 来源:力扣(LeetCode) 22 | * 链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof 23 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | * 25 | * 26 | */ 27 | 28 | class Solution { 29 | public int findRepeatNumber(int[] nums) { 30 | return method_sort(nums); 31 | // return method_set(nums); 32 | } 33 | 34 | private int method_sort(int[] nums) { 35 | Arrays.sort(nums); 36 | 37 | for (int i = 0; i + 1 < nums.length; i++) { 38 | if (nums[i] == nums[i + 1]) 39 | return nums[i]; 40 | } 41 | return -1; 42 | } 43 | 44 | private int method_set(int[] nums) { 45 | Set set = new HashSet<>(); 46 | for (int i = 0; i < nums.length; i++) { 47 | if (set.contains(nums[i])) 48 | return nums[i]; 49 | set.add(nums[i]); 50 | } 51 | return -1; 52 | } 53 | 54 | // 原地置换 ? 55 | 56 | } -------------------------------------------------------------------------------- /Top/01-数组/_75_颜色分类.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 4 | * 5 | * 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 6 | * 7 | * 注意: 不能使用代码库中的排序函数来解决这道题。 8 | * 9 | * 示例: 10 | * 11 | * 输入: [2,0,2,1,1,0] 输出: [0,0,1,1,2,2] 进阶: 12 | * 13 | * 一个直观的解决方案是使用计数排序的两趟扫描算法。 首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 14 | * 你能想出一个仅使用常数空间的一趟扫描算法吗? 15 | * 16 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/sort-colors 17 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 18 | * 19 | * 20 | * 21 | */ 22 | 23 | /** 24 | * 时间复杂度为O(n)的原地排序 系统的排序以及常规的排序方法无法满足O(n)的要求; 25 | * 26 | * 题干中的012是否能给你一些新的思路 27 | * 28 | * 分析: 29 | * 30 | * 三指针: 31 | * 32 | * 遇到1:跳过,红色指针++ 33 | * 34 | * 遇到0:跟绿色指针交换值,绿色指针++,红色指针++ 35 | * 36 | * 遇到2:跟紫色指针交换值,紫色指针--,再次对红色指针的值进行判断 37 | * 38 | * 39 | */ 40 | 41 | class Solution { 42 | public void sortColors(int[] nums) { 43 | int i = 0, l = 0, r = nums.length - 1; 44 | while (i <= r) { 45 | if (nums[i] == 0) { 46 | swap(nums, i++, l++); 47 | } else if (nums[i] == 1) { 48 | i++; 49 | } else { 50 | swap(nums, i, r--); 51 | } 52 | } 53 | } 54 | 55 | private void swap(int[] nums, int i, int j) { 56 | int temp = nums[i]; 57 | nums[i] = nums[j]; 58 | nums[j] = temp; 59 | } 60 | } -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_503. 下一个更大元素 II.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | /** 4 | * 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。 数字 x 5 | * 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。 6 | * 7 | * 示例 1: 8 | * 9 | * 输入: [1,2,1] 输出: [2,-1,2] 10 | * 11 | * 解释: 第一个 1 的下一个更大的数是 2; 数字 2 找不到下一个更大的数; 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。 12 | * 13 | * 注意: 输入数组的长度不会超过 10000。 14 | * 15 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/next-greater-element-ii 16 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 17 | * 18 | */ 19 | 20 | class Solution { 21 | public int[] nextGreaterElements(int[] nums) { 22 | Stack stack = new Stack<>(); 23 | int[] array = new int[nums.length]; 24 | int count = nums.length * 2 - 1; 25 | // 先给数组设置默认值为-1 26 | for (int i = 0; i < array.length; i++) { 27 | array[i] = -1; 28 | } 29 | /** 30 | * 因为是循环数组需要遍历2遍,通过栈找到最大值的index,然后并对输出的数组对饮index赋值 31 | * 一开始stack中我尝试报错数组对应的元素,但是发现无法准备的对array数组对应的index赋值, 32 | * 该题是 496. 下一个更大元素 I 的变种 33 | */ 34 | 35 | for (int i = 0; i < count; i++) { 36 | int idx = i % nums.length; 37 | while (!stack.isEmpty() && nums[idx] > nums[stack.peek()]) { 38 | array[stack.pop()] = nums[idx]; 39 | } 40 | stack.push(idx); 41 | } 42 | return array; 43 | } 44 | } -------------------------------------------------------------------------------- /Top/01-数组/_面试题_16_16_部分排序.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个整数数组,编写一个函数,找出索引m和n,只要将索引区间[m,n]的元素排好序,整个数组就是有序的。注意:n-m尽量最小,也就是说,找出符合条件的最短序列。函数返回值为[m,n],若不存在这样的m和n(例如整个数组是有序的),请返回[-1,-1]。 3 | * 4 | * 示例: 5 | * 6 | * 输入: [1,2,4,7,10,11,7,12,6,7,16,18,19] 输出: [3,9] 提示: 7 | * 8 | * 0 <= len(array) <= 1000000 9 | * 10 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/sub-sort-lcci 11 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 12 | * 13 | * 14 | * 15 | */ 16 | 17 | /** 18 | * 寻找没有排序的部分? 19 | * 20 | * 寻找逆序对 : 21 | * 22 | * 最右边位置的确定: 最左边位置的确定: 23 | * 24 | */ 25 | class Solution { 26 | public int[] subSort(int[] array) { 27 | 28 | if(array == null || array.length < 3) return new int[]{-1,-1}; 29 | 30 | // 从左扫描到右侧 寻找最后一个逆序对 (正序: 递增) 31 | int max = array[0], r = -1; 32 | for (int i = 1; i < array.length; i++) { 33 | if (array[i] >= max) { 34 | max = array[i]; 35 | } else { 36 | r = i; 37 | } 38 | } 39 | 40 | if(r==-1) return new int[]{-1,-1}; 41 | 42 | 43 | // 从右扫描到左侧 寻找最后一个逆序对 (正序: 递增) 44 | int min = array[array.length -1],l = -1; 45 | for (int i = array.length -2 ; i >= 0; i--) { 46 | if (array[i] <= min) { 47 | min = array[i]; 48 | } else { 49 | l = i; 50 | } 51 | } 52 | return new int[]{l,r}; 53 | } 54 | } -------------------------------------------------------------------------------- /Top/05-动态规划/_121_买卖股票的最佳时机.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 4 | * 5 | * 如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。 6 | * 7 | * 注意:你不能在买入股票前卖出股票。 8 | * 9 | *   10 | * 11 | * 示例 1: 12 | * 13 | * 输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 14 | * = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。 示例 2: 15 | * 16 | * 输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 17 | * 18 | * 来源:力扣(LeetCode) 19 | * 链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock 20 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 21 | * 22 | * 23 | */ 24 | 25 | class Solution { 26 | public int maxProfit(int[] prices) { 27 | int minPrice = Integer.MAX_VALUE, profit = 0; 28 | for (int price : prices) { 29 | minPrice = Math.min(minPrice, price); 30 | profit = Math.max(profit, price - minPrice); 31 | } 32 | return profit; 33 | } 34 | 35 | //动态规划解法 36 | /** 37 | * 假设第i天买,第j天的利润是最大的 38 | * 39 | * 第i-j天内,所有相邻两天的股票差的和 40 | * 41 | * 这样该问题可以转化为[最大子数组和]的问题,也就是求[最大连续子序列和]的问题 42 | * 43 | */ 44 | public int maxProfit_dp(int[] prices) { 45 | int minPrice = Integer.MAX_VALUE, profit = 0; 46 | for (int price : prices) { 47 | minPrice = Math.min(minPrice, price); 48 | profit = Math.max(profit, price - minPrice); 49 | } 50 | return profit; 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /Top/02-链表/_86_分隔链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。 4 | * 5 | * 你应当保留两个分区中每个节点的初始相对位置。 6 | * 7 | * 示例: 8 | * 9 | * 输入: head = 1->4->3->2->5->2, x = 3 输出: 1->2->2->4->3->5 10 | * 11 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/partition-list 12 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 13 | * 14 | * 面试题 02.04. 分割链表 15 | */ 16 | 17 | // Definition for singly-linked list. 18 | public class ListNode { 19 | int val; 20 | ListNode next; 21 | 22 | ListNode(int x) { 23 | val = x; 24 | } 25 | } 26 | 27 | // 要求 时间复杂度 O(n),空间复杂度O(1) 28 | class Solution { 29 | public ListNode partition(ListNode head, int x) { 30 | 31 | if (head == null) 32 | return null; 33 | ListNode lHead = new ListNode(0), lTail = lHead; 34 | ListNode rHead = new ListNode(0), rTail = rHead; 35 | 36 | while (head != null) { 37 | if (head.val < x) 38 | lTail = lTail.next = head; 39 | else 40 | rTail = rTail.next = head; 41 | 42 | head = head.next; 43 | } 44 | 45 | /** 46 | * 这句代码很重要,可能会出现以下情况: 47 | * 48 | * 原链表倒数第N个节点A的值是>=x的,A后面所有节点的值都是 Integer.MAX_VALUE) 39 | return 0; 40 | if (result < Integer.MIN_VALUE) 41 | return 0; 42 | x /= 10; 43 | } 44 | return (int) result; 45 | } 46 | 47 | public int reverse_1(int x) { 48 | int result = 0, prevResult = result; 49 | while (x != 0) { 50 | prevResult = result; 51 | int mod = x % 10; 52 | result = prevResult * 10 + mod; 53 | if ((result - mod) / 10 != prevResult) 54 | return 0; 55 | x /= 10; 56 | } 57 | return (int) result; 58 | } 59 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题57-II_和为s的连续正数序列.java: -------------------------------------------------------------------------------- 1 | import java.util.LinkedList; 2 | import java.util.List; 3 | 4 | /** 5 | * 6 | * 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。 7 | * 8 | * 序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。 9 | * 10 | * 示例 1: 11 | * 12 | * 输入:target = 9 13 | * 14 | * 输出:[[2,3,4],[4,5]] 15 | * 16 | * 示例 2: 17 | * 18 | * 输入:target = 15s 19 | * 20 | * 输出:[[1,2,3,4,5],[4,5,6],[7,8]]   21 | * 22 | * 限制: 23 | * 24 | * 1 <= target <= 10^5   25 | * 26 | * 来源:力扣(LeetCode) 27 | * 链接:https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof 28 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 29 | */ 30 | 31 | class Solution { 32 | public int[][] findContinuousSequence(int target) { 33 | 34 | } 35 | 36 | } 37 | 38 | // class Solution { 39 | // public int[][] findContinuousSequence(int target) { 40 | 41 | // List result = new ArrayList<>(); 42 | // int i = 1; 43 | 44 | // while(target>0) 45 | // { 46 | // target -= i++; 47 | // if(target>0 && target%i == 0) 48 | // { 49 | // int[] array = new int[i]; 50 | // for(int k = target/i, j = 0; k < target/i+i; k++,j++) 51 | // { 52 | // array[j] = k; 53 | // } 54 | // result.add(array); 55 | // } 56 | // } 57 | // Collections.reverse(result); 58 | // return result.toArray(new int[0][]); 59 | // } 60 | // } 61 | 62 | // 作者:VaporMax 63 | // 链接:https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/solution/java-shuang-100-by-vapormax/ 64 | // 来源:力扣(LeetCode) 65 | // 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 -------------------------------------------------------------------------------- /Top/03-栈&队列/_面试题_03_04_化栈为队.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 实现一个MyQueue类,该类用两个栈来实现一个队列。 3 | * 4 | * 5 | * 示例: 6 | * 7 | * MyQueue queue = new MyQueue(); 8 | * 9 | * queue.push(1); queue.push(2); queue.peek(); // 返回 1 queue.pop(); // 返回 1 10 | * queue.empty(); // 返回 false 11 | * 12 | * 说明: 13 | * 14 | * 你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size 和 is empty 操作是合法的。 15 | * 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 假设所有操作都是有效的 16 | * (例如,一个空的队列不会调用 pop 或者 peek 操作)。 17 | * 18 | * 来源:力扣(LeetCode) 19 | * 链接:https://leetcode-cn.com/problems/implement-queue-using-stacks-lcci 20 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 21 | * 22 | * 23 | * 24 | */ 25 | 26 | class MyQueue { 27 | 28 | /** Initialize your data structure here. */ 29 | public MyQueue() { 30 | 31 | } 32 | 33 | /** Push element x to the back of queue. */ 34 | public void push(int x) { 35 | 36 | } 37 | 38 | /** Removes the element from in front of queue and returns that element. */ 39 | public int pop() { 40 | 41 | } 42 | 43 | /** Get the front element. */ 44 | public int peek() { 45 | 46 | } 47 | 48 | /** Returns whether the queue is empty. */ 49 | public boolean empty() { 50 | 51 | } 52 | } 53 | 54 | /** 55 | * Your MyQueue object will be instantiated and called as such: 56 | * MyQueue obj = new MyQueue(); 57 | * obj.push(x); 58 | * int param_2 = obj.pop(); 59 | * int param_3 = obj.peek(); 60 | * boolean param_4 = obj.empty(); 61 | */ -------------------------------------------------------------------------------- /剑指Offer/_面试题50_第一个只出现一次的字符.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | import java.util.LinkedHashMap; 3 | import java.util.Map; 4 | 5 | /** 6 | * 在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。 7 | * 8 | * 示例: 9 | * 10 | * s = "abaccdeff" 返回 "b" 11 | * 12 | * s = "" 返回 " "   13 | * 14 | * 限制: 15 | * 16 | * 0 <= s 的长度 <= 50000 17 | * 18 | * 来源:力扣(LeetCode) 19 | * 链接:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof 20 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 21 | * 22 | * 23 | * 24 | * 25 | */ 26 | class Solution { 27 | public char firstUniqChar(String s) { 28 | if (s == null || s.length() == 0) 29 | return ' '; 30 | 31 | } 32 | 33 | static char firstUniqChar_map(String s) { 34 | HashMap map = new HashMap<>(); 35 | char[] chars = s.toCharArray(); 36 | for (char c : chars) 37 | map.put(c, !map.containsKey(c)); 38 | for (char c : chars) 39 | if (map.get(c)) 40 | return c; 41 | return ' '; 42 | } 43 | 44 | static char firstUniqChar_linkedMap(String s) { 45 | LinkedHashMap map = new LinkedHashMap<>(); 46 | char[] chars = s.toCharArray(); 47 | for (char c : chars) 48 | map.put(c, !map.containsKey(c)); 49 | for (Map.Entry e : map.entrySet()) 50 | if (e.getValue().booleanValue()) 51 | return e.getKey(); 52 | 53 | return ' '; 54 | } 55 | } -------------------------------------------------------------------------------- /Top/08-高频题/_54_螺旋矩阵.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 4 | 5 | 示例 1: 6 | 7 | 输入: 8 | [ 9 | [ 1, 2, 3 ], 10 | [ 4, 5, 6 ], 11 | [ 7, 8, 9 ] 12 | ] 13 | 输出: [1,2,3,6,9,8,7,4,5] 14 | 示例 2: 15 | 16 | 输入: 17 | [ 18 | [1, 2, 3, 4], 19 | [5, 6, 7, 8], 20 | [9,10,11,12] 21 | ] 22 | 输出: [1,2,3,4,8,12,11,10,9,5,6,7] 23 | 24 | 来源:力扣(LeetCode) 25 | 链接:https://leetcode-cn.com/problems/spiral-matrix 26 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * 28 | * 29 | * 30 | * 31 | */ 32 | 33 | 34 | class Solution { 35 | public List spiralOrder(int[][] matrix) { 36 | List ans = new ArrayList(); 37 | if (matrix == null || matrix.length == 0) 38 | return ans; 39 | int R = matrix.length, C = matrix[0].length; 40 | boolean[][] seen = new boolean[R][C]; 41 | int[] dr = { 0, 1, 0, -1 }; // 行上下左右方向 42 | int[] dc = { 1, 0, -1, 0 }; // 列上下左右方向 43 | int r = 0, c = 0, di = 0; 44 | for (int i = 0; i < R * C; i++) { 45 | ans.add(matrix[r][c]); 46 | seen[r][c] = true; 47 | int cr = r + dr[di]; 48 | int cc = c + dc[di]; 49 | if (cr >= 0 && cc >= 0 && cr < R && cc < C && !seen[cr][cc]) { 50 | r = cr; 51 | c = cc; 52 | } else { 53 | //如果越界了修改方向 54 | di = (di + 1) % 4; 55 | r += dr[di]; 56 | c += dc[di]; 57 | } 58 | } 59 | return ans; 60 | } 61 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题09_用两个栈实现队列.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 维护两个栈,第一个栈存储元素,第二个栈用于辅助操作。 3 | * 4 | * 根据栈的特性,第一个栈的底部元素是最后插入的元素,第一个栈的顶部元素是下一个被删除的元素。为了维护队列的特性,每次插入的元素应该在第一个栈的底部。因此每次插入元素时,若第一个栈内已经有元素,应将已有的全部元素依次弹出并压入第二个栈,然后将新元素压入第一个栈,最后将第二个栈内的全部元素依次弹出并压入第一个栈。经过上述操作,新插入的元素在第一个栈的底部,第一个栈内的其余元素的顺序和插入元素之前保持一致。 5 | * 6 | * 删除元素时,若第一个栈非空,则直接从第一个栈内弹出一个元素并返回,若第一个栈为空,则返回 -1。 7 | * 8 | * 另外维护队列的元素个数,用于判断队列是否为空。初始元素个数为 0。每次插入元素,元素个数加 1。每次删除元素,元素个数减 1。 9 | * 10 | * 作者:LeetCode-Solution 11 | * 链接:https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/solution/mian-shi-ti-09-yong-liang-ge-zhan-shi-xian-dui-l-3/ 12 | * 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 13 | * 14 | */ 15 | 16 | class CQueue { 17 | Stack stack1; 18 | Stack stack2 = new Stack<>(); 19 | int size; 20 | 21 | public CQueue() { 22 | stack1 = new Stack<>(); 23 | stack2 = new Stack<>(); 24 | size = 0; 25 | 26 | } 27 | 28 | public void appendTail(int value) { 29 | while (!stack1.isEmpty()) 30 | stack2.push(stack1.pop()); 31 | stack1.push(value); 32 | while (!stack2.isEmpty()) 33 | stack1.push(stack2.pop()); 34 | size++; 35 | } 36 | 37 | public int deleteHead() { 38 | if (size == 0) 39 | return -1; 40 | size--; 41 | return stack1.pop(); 42 | } 43 | } 44 | 45 | /** 46 | * Your CQueue object will be instantiated and called as such: CQueue obj = new 47 | * CQueue(); obj.appendTail(value); int param_2 = obj.deleteHead(); 48 | */ -------------------------------------------------------------------------------- /Top/06-二叉树/_236_二叉树的最近公共祖先.java: -------------------------------------------------------------------------------- 1 | import apple.laf.JRSUIUtils.Tree; 2 | 3 | /** 4 | * 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 5 | * 6 | * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 7 | * 的深度尽可能大(一个节点也可以是它自己的祖先)。” 8 | * 9 | * 例如,给定如下二叉树:  root = [3,5,1,6,2,0,8,null,null,7,4] 10 | * 11 | * 12 | * 13 | *   14 | * 15 | * 示例 1: 16 | * 17 | * 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 输出: 3 解释: 节点 5 和节点 1 18 | * 的最近公共祖先是节点 3。 示例 2: 19 | * 20 | * 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 输出: 5 解释: 节点 5 和节点 4 21 | * 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。   22 | * 23 | * 说明: 24 | * 25 | * 所有节点的值都是唯一的。 p、q 为不同节点且均存在于给定的二叉树中。 26 | * 27 | * 来源:力扣(LeetCode) 28 | * 链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree 29 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 30 | * 31 | * 32 | * 33 | * 34 | */ 35 | 36 | // Definition for a binary tree node. 37 | public class TreeNode { 38 | int val; 39 | TreeNode left; 40 | TreeNode right; 41 | 42 | TreeNode(int x) { 43 | val = x; 44 | } 45 | } 46 | 47 | 48 | class Solution { 49 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 50 | if (root == null || root == p || root == q) 51 | return root; 52 | 53 | Tree left = lowestCommonAncestor(root.left, p, q); 54 | Tree right = lowestCommonAncestor(root.left, p, q); 55 | 56 | if (left != null && right != null) 57 | return root; 58 | return (left != null) ? left : right; 59 | } 60 | } -------------------------------------------------------------------------------- /Top/01-数组/_977_有序数组的平方.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 给定一个按非递减顺序排序的整数数组 A,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。 5 | * 6 | *   7 | * 8 | * 示例 1: 9 | * 10 | * 输入:[-4,-1,0,3,10] 输出:[0,1,9,16,100] 示例 2: 11 | * 12 | * 输入:[-7,-3,2,3,11] 输出:[4,9,9,49,121]   13 | * 14 | * 提示: 15 | * 16 | * 1 <= A.length <= 10000 -10000 <= A[i] <= 10000 A 已按非递减顺序排序。 17 | * 18 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/squares-of-a-sorted-array 19 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 20 | * 21 | * 22 | * 23 | */ 24 | 25 | class Solution { 26 | public int[] sortedSquares(int[] A) { 27 | return sortedSquares_DoublePointer(A); 28 | } 29 | 30 | static int[] sortedSquares_Sort(int[] A) { 31 | for (int i = 0; i < A.length; i++) 32 | A[i] *= A[i]; 33 | Arrays.sort(A); 34 | return A; 35 | } 36 | 37 | static int[] sortedSquares_DoublePointer(int[] A) { 38 | int count = 0; 39 | for (int i = 0; i < A.length; i++) { 40 | if (A[i] > 0) 41 | count++; 42 | A[i] *= A[i]; 43 | } 44 | 45 | int[] tempNums = new int[count]; 46 | for (int i = 0; i < A.length; i++) 47 | if (i < count) { 48 | tempNums[i] = A[A.length - count + i]; 49 | } 50 | while (idx2 >= 0) { 51 | if (idx1 < A.length - count && A[idx1] > tempNums[idx2]) 52 | result[cur--] = A[idx1--]; 53 | else 54 | result[cur--] = tempNums[idx2--]; 55 | } 56 | return result; 57 | } 58 | } -------------------------------------------------------------------------------- /Top/02-链表/_2_两数相加.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 4 | * 5 | * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 6 | * 7 | * 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 8 | * 9 | * 示例: 10 | * 11 | * 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 12 | * 13 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/add-two-numbers 14 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 15 | * 16 | */ 17 | 18 | // Definition for singly-linked list. 19 | public class ListNode { 20 | int val; 21 | ListNode next; 22 | 23 | ListNode(int x) { 24 | val = x; 25 | } 26 | } 27 | 28 | class Solution { 29 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 30 | if (l1 == null) 31 | return l2; 32 | if (l2 == null) 33 | return l1; 34 | 35 | ListNode dummyHead = new ListNode(0), last = dummyHead; 36 | int v1 = 0, v2 = 0, carry = 0, sum; 37 | while (l1 != null || l2 != null) { 38 | v1 = 0; 39 | v2 = 0; 40 | if (l1 != null) { 41 | v1 = l1.val; 42 | l1 = l1.next; 43 | } 44 | if (l2 != null) { 45 | v2 = l2.val; 46 | l2 = l2.next; 47 | } 48 | sum = v1 + v2 + carry; 49 | carry = sum / 10; 50 | last.next = new ListNode(sum % 10); 51 | last = last.next; 52 | } 53 | if (carry > 0) { 54 | last.next = new ListNode(carry); 55 | } 56 | return dummyHead.next; 57 | } 58 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题38_字符串的排列.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | 3 | /** 4 | * 输入一个字符串,打印出该字符串中字符的所有排列。 5 | * 6 | * 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。 7 | * 8 | * 示例: 9 | * 10 | * 输入:s = "abc" 输出:["abc","acb","bac","bca","cab","cba"]   11 | * 12 | * 限制: 13 | * 14 | * 1 <= s 的长度 <= 8 15 | * 16 | * 来源:力扣(LeetCode) 17 | * 链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof 18 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 19 | * 20 | * 21 | */ 22 | 23 | /** 24 | * 25 | * 作者:jyd 26 | * 链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/solution/mian-shi-ti-38-zi-fu-chuan-de-pai-lie-hui-su-fa-by/ 27 | * 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 28 | */ 29 | class Solution { 30 | List res = new LinkedList<>(); 31 | char[] c; 32 | 33 | public String[] permutation(String s) { 34 | c = s.toCharArray(); 35 | dfs(0); 36 | return res.toArray(new String[res.size()]); 37 | } 38 | 39 | void dfs(int x) { 40 | if (x == c.length - 1) { 41 | res.add(String.valueOf(c)); // 添加排列方案 (遍历到最后一层) 42 | return; 43 | } 44 | HashSet set = new HashSet<>(); 45 | for (int i = x; i < c.length; i++) { 46 | if (set.contains(c[i])) 47 | continue; // 重复,因此剪枝 48 | set.add(c[i]); 49 | swap(i, x); // 交换,将 c[i] 固定在第 x 位 50 | dfs(x + 1); // 开启固定第 x + 1 位字符 51 | swap(i, x); // 恢复交换 52 | } 53 | } 54 | 55 | void swap(int a, int b) { 56 | char tmp = c[a]; 57 | c[a] = c[b]; 58 | c[b] = tmp; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Top/08-高频题/_50_Pow(x, n).java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 4 | * 5 | * 示例 1: 6 | * 7 | * 输入: 2.00000, 10 输出: 1024.00000 示例 2: 8 | * 9 | * 输入: 2.10000, 3 输出: 9.26100 示例 3: 10 | * 11 | * 输入: 2.00000, -2 输出: 0.25000 解释: 2-2 = 1/22 = 1/4 = 0.25 说明: 12 | * 13 | * -100.0 < x < 100.0 n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。 14 | * 15 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/powx-n 16 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 17 | * 18 | * 19 | */ 20 | 21 | class Solution { 22 | public double myPow(double x, int n) { 23 | 24 | } 25 | 26 | // 递归 时间和空间复杂度 O(nlogn) 27 | public double myPow_recursion(double x, int n) { 28 | /** 29 | * 快速幂 分治思想 30 | */ 31 | // 是否为负数 32 | if (n == 0) 33 | return 1; 34 | if (n == -1) 35 | return 1 / x; 36 | boolean odd = (n & 1) == 1; 37 | // 因为右移运算符的问题 -1 右移多少位都是-1 负奇数右移和负奇数除以二不登记啊 38 | double half = myPow(x, n >> 1); 39 | half *= half; 40 | // x = (n<0)?(1/x):x; 41 | return odd ? (half * x) : half; 42 | } 43 | 44 | // 非递归 45 | public double myPow_notRecursion(double x, int n) { 46 | boolean neg = n < 0; 47 | long y = neg ? -(long) n : n; 48 | double result = 1.0; 49 | 50 | while (y > 0) { 51 | if ((y & 1) == 1) { 52 | // 如果最后一个二进制是1 的累乘 53 | result *= x; 54 | } 55 | x *= x; 56 | y >>= 1; 57 | } 58 | return neg ? (1 / result) : result; 59 | } 60 | 61 | // 取值范围有坑 负数的绝对值 溢出 62 | 63 | } -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/深度优先搜索(DFS)模板.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 深度优先搜索(DFS) 4 | 5 | ``深度优先搜索(DFS)``在大多数情况下,我们在能使用 BFS 时也可以使用 DFS。但是有一个重要的区别:``遍历顺序``。 6 | 7 | 与 BFS 不同,更早访问的结点可能不是更靠近根结点的结点。因此,你在 DFS 中找到的第一条路径可能不是最短路径。通过 **遍历** + **回溯** 的方式进行 8 | 9 | 10 | 11 | 12 | 13 | 14 | ### 模板 - 递归 15 | 16 | 17 | ```java 18 | /* 19 | * Return true if there is a path from cur to target. 20 | */ 21 | boolean DFS(Node cur, Node target, Set visited) { 22 | return true if cur is target; 23 | for (next : each neighbor of cur) { 24 | if (next is not in visited) { 25 | add next to visted; 26 | return true if DFS(next, target, visited) == true; 27 | } 28 | } 29 | return false; 30 | } 31 | ``` 32 | 当我们递归地实现 DFS 时,似乎不需要使用任何栈。但实际上,我们使用的是由系统提供的隐式栈,也称为调用栈(Call Stack)。 33 | 34 | 如果你想找到最短路径呢?再添加一个参数来指示你已经找到的最短路径。 35 | 36 | 37 | 38 | 39 | 40 | ### 模板 II 41 | 递归解决方案的优点是它更容易实现。 但是,存在一个很大的缺点:如果递归的深度太高,你将遭受堆栈溢出。 在这种情况下,您可能会希望使用 BFS,或使用显式栈实现 DFS。 42 | 43 | 这里我们提供了一个使用显式栈的模板: 44 | 45 | ```java 46 | /* 47 | * Return true if there is a path from cur to target. 48 | */ 49 | boolean DFS(int root, int target) { 50 | Set visited; 51 | Stack s; 52 | add root to s; 53 | while (s is not empty) { 54 | Node cur = the top element in s; 55 | return true if cur is target; 56 | for (Node next : the neighbors of cur) { 57 | if (next is not in visited) { 58 | add next to s; 59 | add next to visited; 60 | } 61 | } 62 | remove cur from s; 63 | } 64 | return false; 65 | } 66 | ``` 67 | 该逻辑与递归解决方案完全相同。 但我们使用 while 循环和栈来模拟递归期间的系统调用栈。 手动运行几个示例肯定会帮助你更好地理解它。 -------------------------------------------------------------------------------- /Top/07-DFS/_46_全排列_2.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.List; 3 | 4 | /** 5 | * 6 | * 给定一个 没有重复 数字的序列,返回其所有可能的全排列。 7 | * 8 | * 示例: 9 | * 10 | * 输入: [1,2,3] 11 | 输出: 12 | [ 13 | [1,2,3], 14 | [1,3,2], 15 | [2,1,3], 16 | [2,3,1], 17 | [3,1,2], 18 | [3,2,1] 19 | ] 20 | 21 | 来源:力扣(LeetCode) 22 | 链接:https://leetcode-cn.com/problems/permutations 23 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | * 25 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/permutations 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * 28 | * 29 | */ 30 | 31 | /** 32 | * 33 | * 34 | * 35 | * 36 | * 37 | */ 38 | class Solution { 39 | 40 | public List> permute(int[] nums) { 41 | if (nums == null) 42 | return null; 43 | List> list = new ArrayList<>(); 44 | if (nums.length == 0) 45 | return list; 46 | dfs(0, nums, list); 47 | return list; 48 | } 49 | 50 | private void dfs(int idx, int[] nums, List> list) { 51 | // 不能再往下搜索 52 | if (idx == nums.length) { 53 | List element = new ArrayList<>(); 54 | for (int value : nums) 55 | element.add(value); 56 | list.add(element); 57 | return; 58 | } 59 | // 枚举这一层所有可以做出的选择 60 | for (int i = idx; i < nums.length; i++) { 61 | swap(nums,idx, i); 62 | dfs(idx + 1, nums, list); 63 | swap(nums,idx, i); 64 | } 65 | } 66 | 67 | private void swap(int[] nums, int i, int j) { 68 | int temp = nums[i]; 69 | nums[i] = nums[j]; 70 | nums[j] = temp; 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /Leetcode/_1143_最长公共子序列.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。 4 | * 5 | * 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。 6 | * 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 7 | * 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。 8 | * 9 | * 若这两个字符串没有公共子序列,则返回 0。 10 | * 11 | *   12 | * 13 | * 示例 1: 14 | * 15 | * 输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace",它的长度为 3。 示例 2: 16 | * 17 | * 输入:text1 = "abc", text2 = "abc" 输出:3 解释:最长公共子序列是 "abc",它的长度为 3。 示例 3: 18 | * 19 | * 输入:text1 = "abc", text2 = "def" 输出:0 解释:两个字符串没有公共子序列,返回 0。   20 | * 21 | * 提示: 22 | * 23 | * 1 <= text1.length <= 1000 1 <= text2.length <= 1000 输入的字符串只含有小写英文字符。 24 | * 25 | * 来源:力扣(LeetCode) 26 | * 链接:https://leetcode-cn.com/problems/longest-common-subsequence 27 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 28 | * 29 | */ 30 | 31 | class Solution { 32 | public int longestCommonSubsequence(String text1, String text2) { 33 | if (text1.length() == 0 || text1 == null) 34 | return 0; 35 | if (text2.length() == 0 || text2 == null) 36 | return 0; 37 | 38 | int[][] dp = new int[text1.length() + 1][text2.length() + 1]; 39 | for (int i = 1; i <= text1.length(); i++) { 40 | for (int j = 1; j <= text2.length(); j++) { 41 | char c1 = text1.charAt(i-1); 42 | char c2 = text2.charAt(j-1); 43 | if (c1 == c2) { 44 | dp[i][j] = dp[i - 1][j - 1] + 1; 45 | } else { 46 | dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); 47 | } 48 | } 49 | } 50 | return dp[text1.length()][text2.length()]; 51 | } 52 | } -------------------------------------------------------------------------------- /Top/07-DFS/_17_电话号码的字母组合.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | 3 | /** 4 | * 5 | * 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 6 | * 7 | * 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 8 | * 9 | * 10 | * 示例: 11 | * 12 | * 输入:"23" 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 说明: 13 | * 尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。 14 | * 15 | * 来源:力扣(LeetCode) 16 | * 链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number 17 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 18 | * 19 | */ 20 | 21 | class Solution { 22 | 23 | private char[][] lettersArray = { { 'a', 'b', 'c' }, { 'd', 'e', 'f' }, { 'g', 'h', 'i' }, { 'j', 'k', 'l' }, 24 | { 'm', 'n', 'o' }, { 'p', 'q', 'r', 's' }, { 't', 'u', 'v' }, { 'w', 'x', 'y', 'z' } }; 25 | private char[] chars; 26 | /** 用来存储每一层选择的字母 */ 27 | private char[] string; 28 | private List list; 29 | 30 | public List letterCombinations(String digits) { 31 | if (digits == null) 32 | return null; 33 | chars = digits.toCharArray(); 34 | list = new ArrayList<>(); 35 | if (chars.length == 0) 36 | return list; 37 | string = new char[chars.length]; 38 | dfs(0); 39 | return list; 40 | } 41 | 42 | /** 43 | * @param idx 正在搜索第idx层 44 | */ 45 | private void dfs(int idx) { 46 | //递归设置退出条件;已经进入到最后一层了,不能再往下搜索 47 | if (idx == chars.length) { 48 | // 得到了一个正确的解 49 | list.add(new String(string)); 50 | return; 51 | } 52 | char[] letters = lettersArray[chars[idx] - '2']; 53 | for (char letter : letters) { 54 | string[idx] = letter; 55 | dfs(idx + 1); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Top/07-DFS/_46_全排列_1.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.List; 3 | 4 | /** 5 | * 6 | * 给定一个 没有重复 数字的序列,返回其所有可能的全排列。 7 | * 8 | * 示例: 9 | * 10 | * 输入: [1,2,3] 11 | 输出: 12 | [ 13 | [1,2,3], 14 | [1,3,2], 15 | [2,1,3], 16 | [2,3,1], 17 | [3,1,2], 18 | [3,2,1] 19 | ] 20 | 21 | 来源:力扣(LeetCode) 22 | 链接:https://leetcode-cn.com/problems/permutations 23 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | * 25 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/permutations 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * 28 | * 29 | */ 30 | 31 | /** 32 | * 33 | * 34 | * 35 | * 36 | * 37 | */ 38 | class Solution { 39 | public List> permute(int[] nums) { 40 | if (nums == null) 41 | return null; 42 | 43 | List> result = new ArrayList<>(); 44 | if (nums.length == 0) 45 | return result; 46 | // 用来保存每种组合的数组 47 | List elements = new ArrayList<>(); 48 | boolean[] visited = new boolean[nums.length]; 49 | dfs(result, nums, visited, elements); 50 | return result; 51 | } 52 | 53 | private void dfs(List> result, int[] nums, boolean[] visited, List elements) { 54 | 55 | if (elements.size() == nums.length) { 56 | result.add(new ArrayList<>(elements)); 57 | return; 58 | } 59 | for (int i = 0; i < nums.length; i++) { 60 | if (visited[i]) 61 | continue; 62 | visited[i] = true; 63 | elements.add(nums[i]); 64 | dfs(result, nums, visited, elements); 65 | visited[i] = false; 66 | elements.remove(elements.size() - 1); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Top/04-字符串/_1143_最长公共子序列.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。 4 | * 5 | * 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。 6 | * 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 7 | * 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。 8 | * 9 | * 若这两个字符串没有公共子序列,则返回 0。 10 | * 11 | *   12 | * 13 | * 示例 1: 14 | * 15 | * 输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace",它的长度为 3。 示例 2: 16 | * 17 | * 输入:text1 = "abc", text2 = "abc" 输出:3 解释:最长公共子序列是 "abc",它的长度为 3。 示例 3: 18 | * 19 | * 输入:text1 = "abc", text2 = "def" 输出:0 解释:两个字符串没有公共子序列,返回 0。   20 | * 21 | * 提示: 22 | * 23 | * 1 <= text1.length <= 1000 1 <= text2.length <= 1000 输入的字符串只含有小写英文字符。 24 | * 25 | * 来源:力扣(LeetCode) 26 | * 链接:https://leetcode-cn.com/problems/longest-common-subsequence 27 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 28 | * 29 | */ 30 | 31 | //动态规划中LCS 的问题 32 | 33 | 34 | class Solution { 35 | public int longestCommonSubsequence(String text1, String text2) { 36 | if (text1.length() == 0 || text1 == null) 37 | return 0; 38 | if (text2.length() == 0 || text2 == null) 39 | return 0; 40 | 41 | int[][] dp = new int[text1.length() + 1][text2.length() + 1]; 42 | for (int i = 1; i <= text1.length(); i++) { 43 | for (int j = 1; j <= text2.length(); j++) { 44 | char c1 = text1.charAt(i-1); 45 | char c2 = text2.charAt(j-1); 46 | if (c1 == c2) { 47 | dp[i][j] = dp[i - 1][j - 1] + 1; 48 | } else { 49 | dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); 50 | } 51 | } 52 | } 53 | return dp[text1.length()][text2.length()]; 54 | } 55 | } -------------------------------------------------------------------------------- /Top/07-DFS/_47_全排列II.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个可包含重复数字的序列,返回所有不重复的全排列。 4 | 5 | 示例: 6 | 7 | 输入: [1,1,2] 8 | 输出: 9 | [ 10 | [1,1,2], 11 | [1,2,1], 12 | [2,1,1] 13 | ] 14 | 15 | 来源:力扣(LeetCode) 16 | 链接:https://leetcode-cn.com/problems/permutations-ii 17 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 18 | * 19 | * 20 | * 21 | * 22 | * 23 | */ 24 | 25 | /** 26 | * 根据规律进行合理的剪枝 27 | */ 28 | class Solution { 29 | public List> permuteUnique(int[] nums) { 30 | if (nums == null) 31 | return null; 32 | List> list = new ArrayList<>(); 33 | if (nums.length == 0) 34 | return list; 35 | dfs(0, nums, list); 36 | return list; 37 | } 38 | 39 | private void dfs(int idx, int[] nums, List> list) { 40 | // 不能再往下搜索 41 | if (idx == nums.length) { 42 | List element = new ArrayList<>(); 43 | for (int value : nums) 44 | element.add(value); 45 | list.add(element); 46 | return; 47 | } 48 | // 枚举这一层所有可以做出的选择 49 | for (int i = idx; i < nums.length; i++) { 50 | if (isRepeat(nums, idx, i)) 51 | continue; 52 | swap(nums, idx, i); 53 | dfs(idx + 1, nums, list); 54 | swap(nums, idx, i); 55 | } 56 | } 57 | 58 | private boolean isRepeat(int[] nums, int idx, int i) { 59 | for (int j = idx; j < i; j++) { 60 | if (nums[j] = nums[i]) 61 | return true; 62 | } 63 | return false; 64 | } 65 | 66 | private void swap(int[] nums, int i, int j) { 67 | int temp = nums[i]; 68 | nums[i] = nums[j]; 69 | nums[j] = temp; 70 | } 71 | } -------------------------------------------------------------------------------- /Top/07-DFS/_22_括号生成.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.List; 3 | 4 | /** 5 | * 6 | * 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 7 | 8 | 示例: 9 | 10 | 输入:n = 3 11 | 输出:[ 12 | "((()))", 13 | "(()())", 14 | "(())()", 15 | "()(())", 16 | "()()()" 17 | ] 18 | 19 | 来源:力扣(LeetCode) 20 | 链接:https://leetcode-cn.com/problems/generate-parentheses 21 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 22 | * 23 | * 24 | */ 25 | 26 | /** 27 | * 28 | 29 | 30 | 31 | 32 | */ 33 | class Solution { 34 | public List generateParenthesis(int n) { 35 | List result = new ArrayList<>(); 36 | if (n < 0) 37 | return result; 38 | dfs(0, n, n, new char[n << 1], result); 39 | return result; 40 | } 41 | 42 | private void dfs(int idx, int leftRemain, int rightRemain, char[] chars, List result) { 43 | // 因为每一次尝试,都使用新的字符串变量,所以无需回溯 44 | // 在递归终止的时候,直接把它添加到结果集即可,注意与「力扣」第 46 题、第 39 题区分 45 | 46 | if (idx == chars.length) { 47 | result.add(new String(chars)); 48 | return; 49 | } 50 | 51 | // 枚举这一层所有可能的选择 52 | // 选择一种可能之后,进入下一层搜索 53 | 54 | // 什么情况可以选择左括号?左括号的数量 > 0 55 | // 选择左括号,然后进入下一层搜索 56 | if (leftRemain > 0) { 57 | chars[idx] = '('; 58 | dfs(idx + 1, leftRemain - 1, rightRemain, chars, result); 59 | } 60 | 61 | // 当左括号、右括号的数量一样时,只能选择左括号 62 | // 什么情况可以选择右括号?(右括号的数量 > 0) && (右括号的数量 != 左括号的数量) 63 | // 选择右括号,然后进入下一层搜索 64 | if (rightRemain > 0 && leftRemain != rightRemain) { 65 | chars[idx] = ')'; 66 | dfs(idx + 1, leftRemain, rightRemain-1, chars, result); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_279. 完全平方数.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.HashSet; 3 | import java.util.Set; 4 | 5 | /** 6 | * 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。 7 | * 8 | * 你需要让组成和的完全平方数的个数最少。 9 | * 10 | * 示例 1: 11 | * 12 | * 输入: n = 12 输出: 3 解释: 12 = 4 + 4 + 4. 示例 2: 13 | * 14 | * 输入: n = 13 输出: 2 解释: 13 = 4 + 9. 15 | * 16 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/perfect-squares 17 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 18 | */ 19 | 20 | /** 21 | * 22 | * 23 | * 作者:LeetCode 24 | * 链接:https://leetcode-cn.com/problems/perfect-squares/solution/wan-quan-ping-fang-shu-by-leetcode/ 25 | * 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 26 | */ 27 | 28 | class Solution { 29 | public int numSquares(int n) { 30 | 31 | ArrayList square_nums = new ArrayList(); 32 | for (int i = 1; i * i <= n; ++i) { 33 | square_nums.add(i * i); 34 | } 35 | 36 | Set queue = new HashSet(); 37 | queue.add(n); 38 | 39 | int level = 0; 40 | while (queue.size() > 0) { 41 | level += 1; 42 | Set next_queue = new HashSet(); 43 | 44 | for (Integer remainder : queue) { 45 | 46 | for (Integer square : square_nums) { 47 | if (remainder.equals(square)) { 48 | return level; 49 | } else if (remainder < square) { 50 | break; 51 | } else { 52 | next_queue.add(remainder - square); 53 | } 54 | } 55 | } 56 | queue = next_queue; 57 | } 58 | return level; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /11-字符串/src/com/sequence/BruteForce01.java: -------------------------------------------------------------------------------- 1 | package com.sequence; 2 | 3 | public class BruteForce01 { 4 | 5 | public static int indexOf(String text, String pattern) { 6 | return indexOf1(text, pattern); 7 | } 8 | 9 | public static int indexOf1(String text, String pattern) { 10 | 11 | if (text == null || pattern == null) 12 | return -1; 13 | if (text.length() == 0 || pattern.length() == 0) 14 | return -1; 15 | if (pattern.length() > text.length()) 16 | return -1; 17 | 18 | char[] textChars = text.toCharArray(); 19 | char[] patternChars = pattern.toCharArray(); 20 | int tlen = textChars.length; 21 | int plen = patternChars.length; 22 | 23 | int pi = 0, ti = 0, lenDelta = tlen - plen; 24 | // ti - pi 为当前对比字符串的起始位置idx,优化掉一部分比较的次数 25 | while (pi < plen && ti - pi <= lenDelta) { 26 | if (textChars[ti] == patternChars[pi]) { 27 | ti++; 28 | pi++; 29 | } else { 30 | ti -= pi - 1; 31 | pi = 0; 32 | } 33 | } 34 | return (pi == plen) ? (ti - pi) : -1; 35 | } 36 | 37 | public static int indexOf0(String text, String pattern) { 38 | 39 | if (text == null || pattern == null) 40 | return -1; 41 | if (text.length() == 0 || pattern.length() == 0) 42 | return -1; 43 | if (pattern.length() > text.length()) 44 | return -1; 45 | 46 | char[] textChars = text.toCharArray(); 47 | char[] patternChars = pattern.toCharArray(); 48 | int tlen = textChars.length; 49 | int plen = patternChars.length; 50 | 51 | int pi = 0, ti = 0; 52 | while (pi < plen && ti < tlen) { 53 | if (textChars[ti] == patternChars[pi]) { 54 | ti++; 55 | pi++; 56 | } else { 57 | ti -= pi - 1; 58 | pi = 0; 59 | } 60 | } 61 | return (pi == plen) ? (ti - pi) : -1; 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /剑指Offer/_面试题24_反转链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。   示例: 3 | * 4 | * 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL   5 | * 6 | * 限制: 7 | * 8 | * 0 <= 节点个数 <= 5000 9 | * 10 | * 注意:本题与主站 206 题相同:https://leetcode-cn.com/problems/reverse-linked-list/ 11 | * 12 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof 13 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 14 | * 15 | * 16 | */ 17 | 18 | public class ListNode { 19 | int val; 20 | ListNode next; 21 | 22 | ListNode(int x) { 23 | val = x; 24 | } 25 | } 26 | 27 | class Solution { 28 | public ListNode reverseList(ListNode head) { 29 | // return doublePointer(head); 30 | return recursive(head); 31 | } 32 | //方法一:双指针 33 | private ListNode doublePointer(ListNode head) { 34 | if (head == null) 35 | return null; 36 | ListNode pre = null; 37 | ListNode cur = head; 38 | ListNode temp = null; 39 | while (cur != null) { 40 | temp = cur.next; 41 | cur.next = pre; 42 | pre = cur; 43 | cur = temp; 44 | } 45 | return pre; 46 | } 47 | 48 | //方法二:递归 49 | private ListNode recursive(ListNode head) { 50 | // 递归终止条件是当前为空,或者下一个节点为空 51 | if (head == null || head.next == null) { 52 | return head; 53 | } 54 | // 这里的cur就是最后一个节点 55 | ListNode cur = recursive(head.next); 56 | // 这里请配合动画演示理解 57 | // 如果链表是 1->2->3->4->5,那么此时的cur就是5 58 | // 而head是4,head的下一个是5,下下一个是空 59 | // 所以head.next.next 就是5->4 60 | head.next.next = head; 61 | // 防止链表循环,需要将head.next设置为空 62 | head.next = null; 63 | // 每层递归函数都返回cur,也就是最后一个节点 64 | return cur; 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /Leetcode/Array&String/_498.对角线遍历.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | 3 | /** 4 | * 5 | * 给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。 6 | * 7 | *   8 | * 9 | * 示例: 10 | * 11 | * 输入: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] 12 | * 13 | * 输出: [1,2,4,7,5,3,6,8,9] 14 | * 15 | * 解释: 16 | * 17 | *   18 | * 19 | * 说明: 20 | * 21 | * 给定矩阵中的元素总数不会超过 100000 。 22 | * 23 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/diagonal-traverse 24 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 25 | * 26 | * 27 | */ 28 | 29 | class Solution { 30 | public int[] findDiagonalOrder(int[][] matrix) { 31 | if (matrix == null || matrix.length == 0) 32 | return new int[0]; 33 | int rc = matrix.length; // 行数 34 | int cc = matrix[0].length; // 列数 35 | int[] result = new int[rc * cc]; 36 | int k = 0; // 对角线数组的个数 37 | ArrayList tempList = new ArrayList<>(); 38 | // d < 对角线个数 39 | for (int d = 0; d < rc + cc - 1; d++) { 40 | tempList.clear(); 41 | // We need to figure out the "head" of this diagonal 42 | // The elements in the first row and the last column 43 | // are the respective heads. 44 | int r = d < cc ? 0 : d - cc + 1; 45 | int c = d < cc ? d : cc - 1; 46 | 47 | while (r < rc && c > -1) { 48 | tempList.add(matrix[r][c]); 49 | ++r; 50 | --c; 51 | } 52 | // 每偶数次翻转数组 53 | if (d % 2 == 0) { 54 | Collections.reverse(tempList); 55 | } 56 | for (int i = 0; i < tempList.size(); i++) { 57 | result[k++] = tempList.get(i); 58 | } 59 | 60 | } 61 | 62 | return result; 63 | 64 | } 65 | } -------------------------------------------------------------------------------- /剑指Offer/_面试题52_两个链表的第一个公共节点.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | /** 4 | * 如果两个链表没有交点,返回 null. 在返回结果后,两个链表仍须保持原有的结构。 可假定整个链表结构中没有循环。 程序尽量满足 O(n) 5 | * 时间复杂度,且仅用 O(1) 内存。 本题与主站 160 6 | * 题相同:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/ 7 | * 8 | * 来源:力扣(LeetCode) 9 | * 链接:https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof 10 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 11 | * 12 | */ 13 | 14 | // Definition for singly-linked list. 15 | public class ListNode { 16 | int val; 17 | ListNode next; 18 | 19 | ListNode(int x) { 20 | val = x; 21 | next = null; 22 | } 23 | } 24 | 25 | public class Solution { 26 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 27 | return getIntersectionNode_doublePointer(headA, headB); 28 | } 29 | 30 | static ListNode getIntersectionNode_doublePointer(ListNode headA, ListNode headB) { 31 | ListNode pointerA = headA; 32 | ListNode pointerB = headB; 33 | // A+B 和B+A 路程一致 34 | while (pointerA != pointerB) { 35 | pointerA = pointerA == null ? headB : pointerA.next; 36 | pointerB = pointerB == null ? headA : pointerB.next; 37 | } 38 | 39 | return pointerA; 40 | } 41 | 42 | static ListNode getIntersectionNode_map(ListNode headA, ListNode headB) { 43 | ListNode nodeA = headA; 44 | ListNode nodeB = headB; 45 | HashMap map = new HashMap<>(); 46 | 47 | while (nodeA != null) { 48 | map.put(nodeA, nodeA.next); 49 | nodeA = nodeA.next; 50 | } 51 | while (nodeB != null) { 52 | if (map.containsKey(nodeB)) 53 | return nodeB; 54 | nodeB = nodeB.next; 55 | } 56 | return null; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /Leetcode/_300_最长上升子序列.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 300. 最长上升子序列 给定一个无序的整数数组,找到其中最长上升子序列的长度。 3 | * 4 | * 示例: 5 | * 6 | * 输入: [10,9,2,5,3,7,101,18] 7 | * 8 | * 输出: 4 9 | * 10 | * 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 11 | * 12 | * 说明: 13 | * 14 | * 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。 你算法的时间复杂度应该为 O(n2) 。 15 | * 16 | * 进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗? 17 | */ 18 | 19 | class Solution { 20 | 21 | public int lengthOfLIS(int[] nums) { 22 | if (nums.length == 0 || nums == null) 23 | return 0; 24 | return lengthOfLIS_dp(nums); 25 | } 26 | 27 | /** 28 | * 动态规划解法 29 | * 30 | * 查看动态规划文件夹下方法的LIS.java 31 | * 32 | */ 33 | static int lengthOfLIS_dp(int[] nums) { 34 | 35 | int[] dp = new int[nums.length]; 36 | int max = dp[0] = 1; // 递归基 37 | for (int i = 1; i < nums.length; i++) { 38 | dp[i] = 1; // 初始值为1 39 | for (int j = 0; j < i; j++) { 40 | if (nums[i] <= nums[j]) 41 | continue; 42 | dp[i] = Math.max(dp[i], dp[j] + 1); 43 | } 44 | max = Math.max(max, dp[i]); 45 | } 46 | return max; 47 | 48 | } 49 | 50 | 51 | /** 52 | * 53 | * 时间复杂度为 O( nlogn(n) ) 54 | * 55 | * 对牌顶数组的操作(遍历数组并查找合适的位置)可以是用二分法优化 56 | */ 57 | static int lengthOfLIS_pile(int[] nums) { 58 | int len = 0; // 牌堆的数量 59 | int[] top = new int[nums.length]; // 牌顶数组 60 | int begin,end; //将变量提出来,节省空间 61 | for (int num : nums) { 62 | begin = 0 ; 63 | end = len; 64 | while (begin < end) { 65 | int mid = (begin + end) >> 1; 66 | if (num <= top[mid]) { 67 | end = mid; 68 | } else { 69 | begin = mid + 1; 70 | } 71 | } 72 | // 覆盖牌顶 73 | top[begin] = num; 74 | if(begin == len) len++; 75 | } 76 | return len; 77 | } 78 | 79 | 80 | } -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_130. 被围绕的区域.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public void solve(char[][] board) { 3 | 4 | if (board == null || board.length == 0) 5 | return; 6 | 7 | int rc = board.length; // 行数 8 | int cc = board[0].length; // 列数 9 | int islands_count = 0; 10 | 11 | for (int r = 0; r < rc; ++r) { 12 | for (int c = 0; c < cc; ++c) { 13 | 14 | if (board[r][c] == 'O') { 15 | ++islands_count; 16 | Queue queue = new LinkedList<>(); 17 | queue.offer(r * cc + c); 18 | board[r][c] = 'X'; 19 | 20 | while (!queue.isEmpty()) { 21 | int idx = queue.poll(); 22 | int row = idx / cc; 23 | int col = idx % cc; 24 | 25 | if (row - 1 >= 0 && board[row - 1][col] == 'O') { 26 | queue.offer((row - 1) * cc + col); 27 | board[row - 1][col] = 'X'; 28 | } 29 | if (row + 1 < rc - 1 && board[row + 1][col] == 'O') { 30 | queue.offer((row + 1) * cc + col); 31 | board[row + 1][col] = 'X'; 32 | } 33 | if (col - 1 >= 0 && board[row][col - 1] == 'O') { 34 | queue.offer(row * cc + col - 1); 35 | board[row][col - 1] = 'X'; 36 | } 37 | if (col + 1 < cc -1 && board[row][col + 1] == 'O') { 38 | queue.offer(row * cc + col + 1); 39 | board[row][col + 1] = 'X'; 40 | } 41 | 42 | } 43 | 44 | } 45 | 46 | } 47 | 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /Top/07-DFS/_46_全排列_0.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.List; 3 | 4 | /** 5 | * 6 | * 给定一个 没有重复 数字的序列,返回其所有可能的全排列。 7 | * 8 | * 示例: 9 | * 10 | * 输入: [1,2,3] 11 | 输出: 12 | [ 13 | [1,2,3], 14 | [1,3,2], 15 | [2,1,3], 16 | [2,3,1], 17 | [3,1,2], 18 | [3,2,1] 19 | ] 20 | 21 | 来源:力扣(LeetCode) 22 | 链接:https://leetcode-cn.com/problems/permutations 23 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | * 25 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/permutations 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * 28 | * 29 | */ 30 | 31 | /** 32 | * 33 | * 34 | * 35 | * 36 | * 37 | */ 38 | class Solution { 39 | 40 | private List> list; 41 | private int[] nums; 42 | /** 用来保存每一层选择的数字 */ 43 | private int[] result; 44 | /** 用来标记nums中的数字是否被使用过了 */ 45 | private boolean[] used; 46 | 47 | public List> permute(int[] nums) { 48 | if (nums == null) 49 | return null; 50 | list = new ArrayList<>(); 51 | if (nums.length == 0) 52 | return list; 53 | this.nums = nums; 54 | result = new int[nums.length]; 55 | used = new boolean[nums.length]; 56 | dfs(0); 57 | return list; 58 | } 59 | 60 | private void dfs(int idx) { 61 | // 不能再往下搜索 62 | if (idx == nums.length) { 63 | List resultList = new ArrayList<>(); 64 | for (int value : result) { 65 | resultList.add(value); 66 | } 67 | list.add(resultList); 68 | return; 69 | } 70 | 71 | // 枚举这一层所有可以做出的选择 72 | for (int i = 0; i < nums.length; i++) { 73 | if (used[i]) 74 | continue; 75 | result[idx] = nums[i]; 76 | used[i] = true; 77 | 78 | dfs(idx + 1); 79 | 80 | // 还原现场 81 | used[i] = false; 82 | } 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /Top/05-动态规划/_72_编辑距离.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。 3 | * 4 | * 你可以对一个单词进行如下三种操作: 5 | * 6 | * 插入一个字符 7 | * 8 | * 删除一个字符 9 | * 10 | * 替换一个字符   11 | * 12 | * 示例 1: 13 | * 14 | * 输入:word1 = "horse", word2 = "ros" 输出:3 解释: horse -> rorse (将 'h' 替换为 'r') 15 | * rorse -> rose (删除 'r') rose -> ros (删除 'e') 示例 2: 16 | * 17 | * 输入:word1 = "intention", word2 = "execution" 输出:5 解释: intention -> inention 18 | * (删除 't') inention -> enention (将 'i' 替换为 'e') enention -> exention (将 'n' 替换为 19 | * 'x') exention -> exection (将 'n' 替换为 'c') exection -> execution (插入 'u') 20 | * 21 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/edit-distance 22 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 23 | * 24 | * 编辑距离算法被数据科学家广泛应用,是用作机器翻译和语音识别评价标准的基本算法 25 | * 26 | */ 27 | 28 | /** 29 | * 30 | * dp 的含义: 31 | * 32 | * dp的状态转移方程一共有四种情况: 33 | * 34 | * 35 | * 36 | * 37 | */ 38 | class Solution { 39 | public int minDistance(String word1, String word2) { 40 | if (word1 == null || word2 == null) 41 | return 0; 42 | char[] chars1 = word1.toCharArray(); 43 | char[] chars2 = word2.toCharArray(); 44 | int[][] dp = new int[chars1.length + 1][chars2.length + 1]; 45 | // 初始化 46 | // 第0列 47 | for (int i = 1; i <= chars1.length; i++) { 48 | dp[i][0] = i; 49 | } 50 | // 第0行 51 | for (int i = 1; i <= chars2.length; i++) { 52 | dp[0][i] = i; 53 | } 54 | for (int i = 1; i <= chars1.length; i++) { 55 | for (int j = 1; j <= chars2.length; j++) { 56 | int min1 = Math.min(dp[i - 1][j] + 1, dp[i][j-1] + 1); 57 | int min2 = chars1[i-1] == chars2[j-1] ? dp[i - 1][j - 1] : dp[i - 1][j - 1] + 1; 58 | dp[i][j] = Math.min(min1, min2); 59 | } 60 | } 61 | 62 | return dp[chars1.length][chars2.length]; 63 | } 64 | } -------------------------------------------------------------------------------- /Top/02-链表/_00_必须能默写.java: -------------------------------------------------------------------------------- 1 | import sun.security.krb5.internal.crypto.crc32; 2 | 3 | public class ListNode { 4 | int val; 5 | ListNode next; 6 | 7 | ListNode(int x) { 8 | val = x; 9 | } 10 | } 11 | 12 | public class _00_必须能默写 { 13 | 14 | // 翻转链表 时间复杂度O(n),空间复杂度O(1) 15 | public ListNode reverseList(ListNode head) { 16 | ListNode prev = null, tempNext = null; 17 | while (head != null) { 18 | tempNext = head.next; 19 | head.next = prev; 20 | prev = head; 21 | head = tempNext; 22 | } 23 | return prev; 24 | } 25 | 26 | // 获取链表的中间节点 27 | public ListNode middleNode(ListNode head) { 28 | ListNode fast = head, slow = head; 29 | while (fast.next != null && fast.next.next != null) { 30 | slow = slow.next; 31 | fast = fast.next.next; 32 | } 33 | return slow; 34 | } 35 | 36 | // 删除节点 37 | public ListNode removeElements(ListNode head, int val) { 38 | // 哨兵节点 伪节点 39 | ListNode sentinel = new ListNode(0); 40 | sentinel.next = head; 41 | ListNode prev = sentinel, cur = head; 42 | 43 | while (cur != null) { 44 | if (cur.val == val) 45 | prev.next = cur.next; 46 | else 47 | prev = cur; 48 | cur = cur.next; 49 | } 50 | return sentinel.next; 51 | } 52 | 53 | // 合并两个有序链表 54 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 55 | ListNode prehead = new ListNode(-1); 56 | ListNode prev = prehead; 57 | while (l1 != null && l2 != null) { 58 | if (l1.val <= l2.val) { 59 | prev.next = l1; 60 | l1 = l1.next; 61 | } else { 62 | prev.next = l2; 63 | l2 = l2.next; 64 | } 65 | } 66 | prev.next = l1 == null ? l2 : l1; 67 | return prehead.next; 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_232. 用栈实现队列.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | /** 4 | * 使用栈实现队列的下列操作: 5 | * 6 | * push(x) -- 将一个元素放入队列的尾部。 pop() -- 从队列首部移除元素。 peek() -- 返回队列首部的元素。 empty() -- 7 | * 返回队列是否为空。 示例: 8 | * 9 | * MyQueue queue = new MyQueue(); 10 | * 11 | * queue.push(1); queue.push(2); queue.peek(); // 返回 1 queue.pop(); // 返回 1 12 | * queue.empty(); // 返回 false 说明: 13 | * 14 | * 你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 15 | * 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 假设所有操作都是有效的 16 | * (例如,一个空的队列不会调用 pop 或者 peek 操作)。 17 | * 18 | * 来源:力扣(LeetCode) 19 | * 链接:https://leetcode-cn.com/problems/implement-queue-using-stacks 20 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 21 | * 22 | */ 23 | 24 | class MyQueue { 25 | Stack s1 = new Stack<>(); 26 | Stack s2 = new Stack<>(); 27 | 28 | /** Initialize your data structure here. */ 29 | public MyQueue() { 30 | 31 | } 32 | 33 | /** Push element x to the back of queue. */ 34 | public void push(int x) { 35 | while (!s1.isEmpty()) { 36 | s2.push(s1.pop()); 37 | } 38 | s1.push(x); 39 | while (!s2.isEmpty()) { 40 | s1.push(s2.pop()); 41 | } 42 | } 43 | 44 | /** Removes the element from in front of queue and returns that element. */ 45 | public int pop() { 46 | if (s1.isEmpty()) { 47 | return 0; 48 | } 49 | return s1.pop(); 50 | } 51 | 52 | /** Get the front element. */ 53 | public int peek() { 54 | if (s1.isEmpty()) { 55 | return 0; 56 | } 57 | return s1.peek(); 58 | } 59 | 60 | /** Returns whether the queue is empty. */ 61 | public boolean empty() { 62 | return s2.isEmpty(); 63 | } 64 | } 65 | 66 | /** 67 | * Your MyQueue object will be instantiated and called as such: MyQueue obj = 68 | * new MyQueue(); obj.push(x); int param_2 = obj.pop(); int param_3 = 69 | * obj.peek(); boolean param_4 = obj.empty(); 70 | */ -------------------------------------------------------------------------------- /Top/03-栈&队列/_232_用栈实现队列.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | /** 4 | * 5 | * 使用栈实现队列的下列操作: 6 | * 7 | * push(x) -- 将一个元素放入队列的尾部。 pop() -- 从队列首部移除元素。 peek() -- 返回队列首部的元素。 empty() -- 8 | * 返回队列是否为空。   9 | * 10 | * 示例: 11 | * 12 | * MyQueue queue = new MyQueue(); 13 | * 14 | * queue.push(1); queue.push(2); queue.peek(); // 返回 1 queue.pop(); // 返回 1 15 | * queue.empty(); // 返回 false   16 | * 17 | * 说明: 18 | * 19 | * 你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 20 | * 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 假设所有操作都是有效的 21 | * (例如,一个空的队列不会调用 pop 或者 peek 操作)。 22 | * 23 | * 来源:力扣(LeetCode) 24 | * 链接:https://leetcode-cn.com/problems/implement-queue-using-stacks 25 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 26 | * 27 | * 28 | * 29 | */ 30 | 31 | class MyQueue { 32 | Stack mainStack; 33 | Stack tempStack; 34 | 35 | /** Initialize your data structure here. */ 36 | public MyQueue() { 37 | mainStack = new Stack<>(); 38 | tempStack = new Stack<>(); 39 | 40 | } 41 | 42 | /** Push element x to the back of queue. */ 43 | public void push(int x) { 44 | while (!mainStack.isEmpty()) 45 | tempStack.push(mainStack.pop()); 46 | mainStack.push(x); 47 | while (!tempStack.isEmpty()) 48 | mainStack.push(tempStack.pop()); 49 | } 50 | 51 | /** Removes the element from in front of queue and returns that element. */ 52 | public int pop() { 53 | return mainStack.isEmpty() ? 0 : mainStack.pop(); 54 | } 55 | 56 | /** Get the front element. */ 57 | public int peek() { 58 | return mainStack.isEmpty() ? 0 : mainStack.peek(); 59 | } 60 | 61 | /** Returns whether the queue is empty. */ 62 | public boolean empty() { 63 | return mainStack.isEmpty(); 64 | } 65 | } 66 | 67 | /** 68 | * Your MyQueue object will be instantiated and called as such: MyQueue obj = 69 | * new MyQueue(); obj.push(x); int param_2 = obj.pop(); int param_3 = 70 | * obj.peek(); boolean param_4 = obj.empty(); 71 | */ -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_496. 下一个更大元素 I.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.HashMap; 3 | import java.util.Stack; 4 | 5 | /** 6 | * 7 | * 给定两个 没有重复元素 的数组 nums1 8 | * 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。 9 | * 10 | * nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。 11 | * 12 | * 示例 1: 13 | * 14 | * 输入: nums1 = [4,1,2], nums2 = [1,3,4,2]. 输出: [-1,3,-1] 15 | * 16 | * 解释: 对于num1中的数字4,你无法在第二个数组中找到下一个更大的数字,因此输出 -1。 17 | * 对于num1中的数字1,第二个数组中数字1右边的下一个较大数字是 3。 对于num1中的数字2,第二个数组中没有下一个更大的数字,因此输出 -1。 18 | * 19 | * 示例 2: 20 | * 21 | * 输入: nums1 = [2,4], nums2 = [1,2,3,4]. 22 | * 23 | * 输出: [3,-1] 24 | * 25 | * 解释:   对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。 对于 num1 中的数字 4 26 | * ,第二个数组中没有下一个更大的数字,因此输出 -1 。 27 | * 28 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/next-greater-element-i 29 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 30 | * 31 | * 32 | */ 33 | 34 | /** 35 | * 36 | * 刚看到题目确实是有无从下手的感觉,后来是通过观看官方解答的动图理解的. 37 | * 38 | * 题目分析,num1位num2的子集,找到 nums1 中每个元素在 nums2 中的下一个比其大的值。 39 | * 其实求的就是num2中的每个元素,在当前数组中比自己大的下一个元素,如果没有的话,则为-1(暴力破解的话,时间复杂度为n²) 40 | * num1其实是迷惑行为,只要找到上方的要求,再遍历num1就可以 41 | */ 42 | 43 | 44 | 45 | // (栈的经典用法) 46 | class Solution { 47 | public int[] nextGreaterElement(int[] nums1, int[] nums2) { 48 | 49 | HashMap map = new HashMap<>(); 50 | Stack stack = new Stack<>(); 51 | 52 | /** 53 | * 通过stack和map结合,找出比当前元素下一个更大的元素 O(N) 54 | * 55 | */ 56 | for (int i = 0; i < nums2.length; i++) { 57 | while (!stack.isEmpty() && nums2[i] > stack.peek()) { 58 | map.put(stack.pop(), nums2[i]); 59 | } 60 | stack.push(nums2[i]); 61 | } 62 | while (!stack.isEmpty()) { 63 | map.put(stack.pop(), -1); 64 | } 65 | 66 | // 遍历num1(为num2的子集),求出比当前元素在num2中的位置,大的下一个元素 67 | int[] array = new int[nums1.length]; 68 | for (int i = 0; i < nums1.length; i++) { 69 | array[i] = map.get(nums1[i]); 70 | } 71 | return array; 72 | } 73 | } -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_1021. 删除最外层的括号.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | /** 4 | * 有效括号字符串为空 ("")、"(" + A + ")" 或 A + B,其中 A 5 | * 和 B 都是有效的括号字符串,+ 代表字符串的连接。例如,"","()","(())()" 和 "(()(()))" 都是有效的括号字符串。 6 | * 7 | * 如果有效字符串 S 非空,且不存在将其拆分为 S = A+B 的方法,我们称其为原语(primitive),其中 A 和 B 都是非空有效括号字符串。 8 | * 9 | * 给出一个非空有效字符串 S,考虑将其进行原语化分解,使得:S = P_1 + P_2 + ... + P_k,其中 P_i 是有效括号字符串原语。 10 | * 11 | * 对 S 进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 S 。 12 | * 13 | *   14 | * 15 | * 示例 1: 16 | * 17 | * 输入:"(( )( ))(())" 输出:"()()()" 18 | * 19 | * 解释: 输入字符串为 "(()())(())",原语化分解得到 "(()())" + 20 | * "(())", 删除每个部分中的最外层括号后得到 "()()" + "()" = "()()()"。 21 | * 22 | * 示例 2: 23 | * 24 | * 输入:"(()())(())(()(()))" 输出:"()()()()(())" 25 | * 26 | * 解释: 输入字符串为 27 | * "(()())(())(()(()))",原语化分解得到 "(()())" + "(())" + "(()(()))", 删除每个部分中的最外层括号后得到 28 | * "()()" + "()" + "()(())" = "()()()()(())"。 29 | * 30 | * 示例 3: 31 | * 32 | * 输入:"()()" 输出:"" 33 | * 34 | * 解释: 输入字符串为 "()()",原语化分解得到 "()" + "()", 删除每个部分中的最外层括号后得到 "" + 35 | * "" = ""。   36 | * 37 | * 提示: 38 | * S.length <= 10000 S[i] 为 "(" 或 ")" S 是一个有效括号字符串 39 | * 40 | * 来源:力扣(LeetCode) 41 | * 链接:https://leetcode-cn.com/problems/remove-outermost-parentheses 42 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 43 | */ 44 | 45 | 46 | /** 47 | * (左侧括号时入栈,)右侧括号时出栈,当栈空的时候删除首尾的字符, 48 | * 49 | * 删除完成以后需要对start重新赋值 50 | */ 51 | class Solution { 52 | public String removeOuterParentheses(String S) { 53 | Stack stack = new Stack<>(); 54 | StringBuilder string = new StringBuilder(); 55 | int start = 0; 56 | for (int i = 0; i < S.length(); i++) { 57 | char c = S.charAt(i); 58 | string.append(c); 59 | if (c == '(') 60 | stack.push(c); 61 | if (c == ')') 62 | stack.pop(); 63 | 64 | if (stack.isEmpty()) { 65 | string.deleteCharAt(start); 66 | string.deleteCharAt(string.length() - 1); 67 | start = string.length(); 68 | } 69 | } 70 | return string.toString(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /剑指Offer/_面试题39_数组中出现次数超过一半的数字.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | /** 4 | * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。   5 | * 6 | * 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 7 | * 8 | * 示例 1: 9 | * 10 | * 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2   11 | * 12 | * 限制: 13 | * 14 | * 1 <= 数组长度 <= 50000 15 | * 16 | * 注意:本题与主站 169 题相同:https://leetcode-cn.com/problems/majority-element/ 17 | * 18 | * 来源:力扣(LeetCode) 19 | * 链接:https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof 20 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 21 | * 22 | * 23 | * 24 | * 25 | */ 26 | 27 | class Solution { 28 | public int majorityElement(int[] nums) { 29 | return majorityElement_map(nums); 30 | } 31 | 32 | static int majorityElement_map(int[] nums) { 33 | HashMap map = new HashMap<>(); 34 | for (int i = 0; i < nums.length; i++) { 35 | 36 | if (map.containsKey(nums[i])) 37 | map.put(nums[i], map.get(nums[i]) + 1); 38 | else 39 | map.put(nums[i], 1); 40 | 41 | if (map.get(nums[i]) > nums.length / 2) 42 | return nums[i]; 43 | } 44 | return 0; 45 | } 46 | 47 | // 来自评论区大佬的摩尔投票法 因题干已经强调肯定存在数组和众数 48 | static int majorityElement_vote0(int[] nums) { 49 | // votes为票数 ,cur为当前的 "众数" 50 | int votes = 0, cur = 0; 51 | for (int num : nums) { 52 | if (votes == 0) 53 | cur = num; 54 | votes += num == cur ? 1 : -1; 55 | } 56 | return cur; 57 | } 58 | 59 | // 普适方法,若题干未强调肯定存在众数,需要再投票结束完成以后对该 x 进行验证 60 | static int majorityElement_vote1(int[] nums) { 61 | // votes为票数 ,cur为当前的 "众数" 62 | int votes = 0, cur = 0, count = 0; 63 | for (int num : nums) { 64 | if (votes == 0) 65 | cur = num; 66 | votes += num == cur ? 1 : -1; 67 | } 68 | // 验证x是否为众数 69 | for (int num : nums) 70 | if (num == cur) 71 | count++; 72 | return count > nums.length / 2 ? cur : 0; 73 | } 74 | } -------------------------------------------------------------------------------- /Leetcode/Array&String/_54.螺旋矩阵.java: -------------------------------------------------------------------------------- 1 | import java.awt.List; 2 | 3 | /** 4 | * 给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 5 | * 6 | * 示例 1: 7 | * 8 | * 输入: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] 输出: [1,2,3,6,9,8,7,4,5] 9 | * 10 | * 示例 2: 11 | * 12 | * 输入: [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] 13 | * 14 | * 输出: [1,2,3,4,8,12,11,10,9,5,6,7] 15 | * 16 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/spiral-matrix 17 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 18 | * 19 | * 20 | */ 21 | 22 | /** 23 | * 24 | * 绘制螺旋轨迹路径,我们发现当路径超出界限或者进入之前访问过的单元格时,会顺时针旋转方向。 25 | * 26 | * 算法 27 | * 28 | * 假设数组有 {R}R 行 {C}C 列,{seen[r][c]}seen[r][c] 表示第 r 行第 c 列的单元格之前已经被访问过了。当前所在位置为 29 | * {(r, c)}(r, c),前进方向是 {di}di。我们希望访问所有 {R}R x {C}C 个单元格。 30 | * 31 | * 当我们遍历整个矩阵,下一步候选移动位置是 {(cr,cc)}(cr, cc)。 32 | * 33 | * 如果这个候选位置在矩阵范围内并且没有被访问过,那么它将会变成下一步移动的位置;否则,我们将前进方向顺时针旋转之后再计算下一步的移动位置。 34 | * 35 | * 作者:LeetCode 36 | * 链接:https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-leetcode/ 37 | * 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 38 | * 39 | */ 40 | class Solution { 41 | public List spiralOrder(int[][] matrix) { 42 | List ans = new ArrayList(); 43 | if (matrix == null || matrix.length == 0) 44 | return ans; 45 | int R = matrix.length, C = matrix[0].length; 46 | boolean[][] seen = new boolean[R][C]; 47 | int[] dr = { 0, 1, 0, -1 }; // 行上下左右方向 48 | int[] dc = { 1, 0, -1, 0 }; // 列上下左右方向 49 | int r = 0, c = 0, di = 0; 50 | for (int i = 0; i < R * C; i++) { 51 | ans.add(matrix[r][c]); 52 | seen[r][c] = true; 53 | int cr = r + dr[di]; 54 | int cc = c + dc[di]; 55 | if (cr >= 0 && cc >= 0 && cr < R && cc < C && !seen[cr][cc]) { 56 | r = cr; 57 | c = cc; 58 | } else { 59 | //如果越界了修改方向 60 | di = (di + 1) % 4; 61 | r += dr[di]; 62 | c += dc[di]; 63 | } 64 | } 65 | return ans; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Top/08-高频题/_15_三数之和.java: -------------------------------------------------------------------------------- 1 | import java.lang.reflect.Array; 2 | import java.util.ArrayList; 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * 8 | * 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 9 | * ?请你找出所有满足条件且不重复的三元组。 10 | * 11 | * 注意:答案中不可以包含重复的三元组。 12 | * 13 | *   14 | * 15 | * 示例: 16 | * 17 | * 给定数组 nums = [-1, 0, 1, 2, -1, -4], 18 | * 19 | * 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ] 20 | * 21 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/3sum 22 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 23 | * 24 | * 25 | */ 26 | 27 | class Solution { 28 | public List> threeSum(int[] nums) { 29 | /** 30 | * 暴力法 枚举枚举每一对整数 时间复杂度O(n^3) 空间复杂度时间复杂度O(1) 31 | * 32 | * 是否能存在更优解? 33 | * 34 | * 如果数组是有序的呢? 35 | */ 36 | 37 | if (nums == null) 38 | return null; 39 | List> result = new ArrayList<>(); 40 | if (nums.length < 3) 41 | return result; 42 | // 排序 43 | Arrays.sort(nums); 44 | // 用来扫描三元数的第一个元素 45 | int lastIdx = nums.length - 3; 46 | for (int i = 0; i <= lastIdx; i++) { 47 | // 如果相等则跳过 去重 剪枝 48 | if (i > 0 && nums[i] == nums[i - 1]) 49 | continue; 50 | 51 | int l = i + 1, r = nums.length - 1, remain = -nums[i]; 52 | while (l < r) { 53 | int sumLr = nums[l] + nums[r]; 54 | if (sumLr == remain) { 55 | // 找到符合条件的三元组 56 | result.add(Arrays.asList(nums[i], nums[l], nums[r])); 57 | // 跳过相同的值 去重剪枝 58 | while (l < r && nums[l] == nums[l + 1]) 59 | l++; 60 | while (l < r && nums[r] == nums[r - 1]) 61 | r--; 62 | l++; 63 | r--; 64 | } else if (sumLr < remain) { 65 | l++; 66 | } else { 67 | r--; 68 | } 69 | } 70 | } 71 | return result; 72 | } 73 | } -------------------------------------------------------------------------------- /11-字符串/src/com/sequence/KMP.java: -------------------------------------------------------------------------------- 1 | package com.sequence; 2 | 3 | public class KMP { 4 | 5 | public static int indexOf(String text, String pattern) { 6 | if (text == null || pattern == null) 7 | return -1; 8 | if (text.length() == 0 || pattern.length() == 0) 9 | return -1; 10 | char[] textChars = text.toCharArray(); 11 | char[] patternChars = pattern.toCharArray(); 12 | 13 | int tlen = textChars.length; 14 | int plen = patternChars.length; 15 | 16 | if (tlen < plen) 17 | return -1; 18 | // next表 19 | int[] next = next1(pattern); 20 | 21 | int pi = 0, ti = 0, lenDelta = tlen - plen; 22 | while (pi < plen && ti - pi <= lenDelta) { 23 | // pi = -1 时,pi++ 归零 ,ti往后移动一位 24 | if (pi < 0 || textChars[ti] == patternChars[pi]) { 25 | ti++; 26 | pi++; 27 | } else { 28 | pi = next[pi]; 29 | } 30 | } 31 | return (pi == plen) ? (ti - pi) : -1; 32 | } 33 | 34 | /** 35 | * next 数组各值的含义: 36 | * 37 | * 代表当前字符之前的字符串中,相同真前缀后缀的最大长度。 38 | * 39 | * 相当于当前字符串的真前缀后缀的“最大长度值” 整体向右移动一位,然后初始值赋为-1。 40 | * 41 | */ 42 | 43 | private static int[] next1(String pattern) { 44 | char[] chars = pattern.toCharArray(); 45 | int[] next = new int[chars.length]; 46 | 47 | next[0] = -1; 48 | int i = 0; 49 | int n = -1; 50 | 51 | // chars[n]表示前缀,chars[i]表示后缀 52 | int iMax = chars.length - 1; 53 | 54 | while (i < iMax) { 55 | if (n < 0 || chars[i] == chars[n]) { 56 | ++i; 57 | ++n; 58 | if (chars[i] == chars[n]) 59 | next[i] = next[n]; 60 | else 61 | next[i] = n; 62 | } else { 63 | n = next[n]; 64 | } 65 | } 66 | return next; 67 | } 68 | 69 | private static int[] next0(String pattern) { 70 | char[] chars = pattern.toCharArray(); 71 | int[] next = new int[chars.length]; 72 | 73 | next[0] = -1; 74 | int n = -1; 75 | int i = 0; 76 | // chars[n]表示前缀,chars[i]表示后缀 77 | int iMax = chars.length - 1; 78 | 79 | while (i < iMax) { 80 | if (n < 0 || chars[i] == chars[n]) 81 | next[++i] = ++n; 82 | else 83 | n = next[n]; 84 | } 85 | return next; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Top/02-链表/_160_相交链表.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | /** 4 | * 如果两个链表没有交点,返回 null. 在返回结果后,两个链表仍须保持原有的结构。 可假定整个链表结构中没有循环。 程序尽量满足 O(n) 5 | * 时间复杂度,且仅用 O(1) 内存。 本题与主站 160 6 | * 题相同:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/ 7 | * 8 | * 来源:力扣(LeetCode) 9 | * 链接:https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof 10 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 11 | * 12 | * 13 | * 14 | * 面试题 02.07. 链表相交 15 | * 16 | * 面试题52. 两个链表的第一个公共节点 17 | * 18 | */ 19 | 20 | // Definition for singly-linked list. 21 | public class ListNode { 22 | int val; 23 | ListNode next; 24 | 25 | ListNode(int x) { 26 | val = x; 27 | next = null; 28 | } 29 | } 30 | 31 | public class Solution { 32 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 33 | return getIntersectionNode_doublePointer(headA, headB); 34 | } 35 | 36 | static ListNode getIntersectionNode_doublePointer(ListNode headA, ListNode headB) { 37 | ListNode pointerA = headA; 38 | ListNode pointerB = headB; 39 | // A+B 和B+A 路程一致 40 | while (pointerA != pointerB) { 41 | pointerA = pointerA == null ? headB : pointerA.next; 42 | pointerB = pointerB == null ? headA : pointerB.next; 43 | // 如果两个不相交的链表就会死循环 44 | // pointerA = pointerA.next == null ? headB : pointerA.next; 45 | // pointerB = pointerB.next == null ? headA : pointerB.next; 46 | } 47 | 48 | return pointerA; 49 | } 50 | 51 | static ListNode getIntersectionNode_map(ListNode headA, ListNode headB) { 52 | ListNode nodeA = headA; 53 | ListNode nodeB = headB; 54 | HashMap map = new HashMap<>(); 55 | 56 | while (nodeA != null) { 57 | map.put(nodeA, nodeA.next); 58 | nodeA = nodeA.next; 59 | } 60 | while (nodeB != null) { 61 | if (map.containsKey(nodeB)) 62 | return nodeB; 63 | nodeB = nodeB.next; 64 | } 65 | return null; 66 | } 67 | 68 | A ____ 69 | _________ 70 | 71 | B 72 | _________ ____ 73 | } -------------------------------------------------------------------------------- /Top/08-高频题/_146_LRU缓存机制_01.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 4 | * 5 | * 获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。 写入数据 put(key, 6 | * value) - 7 | * 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。 8 | * 9 | *   10 | * 11 | * 进阶: 12 | * 13 | * 你是否可以在 O(1) 时间复杂度内完成这两种操作? 14 | * 15 | *   16 | * 17 | * 示例: 18 | * 19 | * LRUCache cache = new LRUCache( 2) //缓存容量; 20 | * 21 | * cache.put(1, 1); cache.put(2, 2); cache.get(1); // 返回 1 cache.put(3, 3); // 22 | * 该操作会使得关键字 2 作废 cache.get(2); // 返回 -1 (未找到) cache.put(4, 4); // 该操作会使得关键字 1 23 | * 作废 cache.get(1); // 返回 -1 (未找到) cache.get(3); // 返回 3 cache.get(4); // 返回 4 24 | * 25 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/lru-cache 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * 28 | * 29 | * 30 | * 31 | * 32 | */ 33 | 34 | /** 35 | * 36 | * 37 | * 要让 put 和 get 方法的时间复杂度为 O(1)O(1),我们可以总结出 cache 这个数据结构必要的条件:查找快,插入快,删除快,有顺序之分。 38 | * 39 | * 因为显然 cache 必须有顺序之分,以区分最近使用的和久未使用的数据;而且我们要在 cache 40 | * 中查找键是否已存在;如果容量满了要删除最后一个数据;每次访问还要把数据插入到队头。 41 | * 42 | * 那么,什么数据结构同时符合上述条件呢?哈希表查找快,但是数据无固定顺序;链表有顺序之分,插入删除快,但是查找慢。所以结合一下,形成一种新的数据结构:哈希链表。 43 | * 44 | * 作者:labuladong 45 | * 链接:https://leetcode-cn.com/problems/lru-cache/solution/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/ 46 | * 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 47 | * 48 | * 49 | */ 50 | 51 | class LRUCache extends LinkedHashMap { 52 | private int capacity; 53 | 54 | public LRUCache(int capacity) { 55 | super(capacity, 0.75F, true); 56 | this.capacity = capacity; 57 | } 58 | 59 | public int get(int key) { 60 | return super.getOrDefault(key, -1); 61 | } 62 | 63 | public void put(int key, int value) { 64 | super.put(key, value); 65 | 66 | } 67 | @Override 68 | protected boolean removeEldestEntry(Map.Entry eldest) { 69 | return size() > capacity; 70 | } 71 | } 72 | 73 | /** 74 | * Your LRUCache object will be instantiated and called as such: LRUCache obj = 75 | * new LRUCache(capacity); int param_1 = obj.get(key); obj.put(key,value); 76 | */ -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_155. 最小栈.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | /** 4 | * 5 | * 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 6 | * 7 | * push(x) —— 将元素 x 推入栈中。 pop() —— 删除栈顶的元素。 top() —— 获取栈顶元素。 getMin() —— 8 | * 检索栈中的最小元素。 示例: 9 | * 10 | * MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); 11 | * minStack.push(-3); minStack.getMin(); --> 返回 -3. minStack.pop(); 12 | * minStack.top(); --> 返回 0. minStack.getMin(); --> 返回 -2. 13 | * 14 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/min-stack 15 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 16 | * 17 | */ 18 | 19 | class MinStack { 20 | 21 | Stack mainStack = new Stack<>(); 22 | Stack minStack = new Stack<>(); 23 | 24 | /** initialize your data structure here. */ 25 | public MinStack() { 26 | 27 | } 28 | 29 | public void push(int x) { 30 | mainStack.push(x); 31 | if (minStack.isEmpty() || x <= minStack.peek()) { 32 | minStack.push(x); 33 | } 34 | } 35 | 36 | public void pop() { 37 | 38 | /** 39 | * 注意:下方的equals 使用 == 进行判断的时候,代码提交报错 见图片001.png 40 | * 41 | * 原因如下: Java中 Integer在常量池中的存储范围为[-128,127],127在这范围内,因此是直接存储于常量池的, 42 | * 而超过127的值不在这范围内,所以会在堆内存中创建一个新的对象来保存这个值, 所以m,n分别指向了两个不同的对象地址,故而导致了不相等。 43 | * 44 | * 关联知识点: 45 | * https://blog.csdn.net/lcsy000/article/details/82782864 46 | */ 47 | if (mainStack.pop().equals(minStack.peek())) { 48 | minStack.pop(); 49 | } 50 | } 51 | 52 | public int top() { 53 | /** 54 | * 因为该返会返回值为int类型,需要对栈空的情况做处理,抛异常或者返会0 55 | */ 56 | if (mainStack.isEmpty()) { 57 | return 0; 58 | } 59 | return mainStack.peek(); 60 | } 61 | 62 | public int getMin() { 63 | /** 64 | * 因为该返会返回值为int类型,需要对栈空的情况做处理,抛异常或者返会0 65 | */ 66 | if (minStack.isEmpty()) { 67 | return 0; 68 | } 69 | return minStack.peek(); 70 | } 71 | } 72 | 73 | /** 74 | * Your MinStack object will be instantiated and called as such: MinStack obj = 75 | * new MinStack(); obj.push(x); obj.pop(); int param_3 = obj.top(); int param_4 76 | * = obj.getMin(); 77 | */ -------------------------------------------------------------------------------- /00.数据结构/src/circle/CircleQueue.java: -------------------------------------------------------------------------------- 1 | package circle; 2 | 3 | @SuppressWarnings("unchecked") 4 | public class CircleQueue { 5 | private int front; 6 | private int size; 7 | private E[] elements; 8 | private static final int DEFAULT_CAPACITY = 10; 9 | 10 | public CircleQueue() { 11 | elements = (E[]) new Object[DEFAULT_CAPACITY]; 12 | } 13 | 14 | public int size() { 15 | return size; 16 | } 17 | 18 | public boolean isEmpty() { 19 | return size == 0; 20 | } 21 | 22 | public void clear() { 23 | for (int i = 0; i < size; i++) { 24 | elements[index(i)] = null; 25 | } 26 | front = 0; 27 | size = 0; 28 | } 29 | 30 | public void enQueue(E element) { 31 | ensureCapacity(size + 1); 32 | 33 | elements[index(size)] = element; 34 | size++; 35 | } 36 | 37 | public E deQueue() { 38 | E frontElement = elements[front]; 39 | elements[front] = null; 40 | front = index(1); 41 | size--; 42 | return frontElement; 43 | } 44 | 45 | public E front() { 46 | return elements[front]; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | StringBuilder string = new StringBuilder(); 52 | string.append("capcacity=").append(elements.length) 53 | .append(" size=").append(size) 54 | .append(" front=").append(front) 55 | .append(", ["); 56 | for (int i = 0; i < elements.length; i++) { 57 | if (i != 0) { 58 | string.append(", "); 59 | } 60 | 61 | string.append(elements[i]); 62 | } 63 | string.append("]"); 64 | return string.toString(); 65 | } 66 | 67 | private int index(int index) { 68 | index += front; 69 | return index - (index >= elements.length ? elements.length : 0); 70 | } 71 | 72 | /** 73 | * 保证要有capacity的容量 74 | * @param capacity 75 | */ 76 | private void ensureCapacity(int capacity) { 77 | int oldCapacity = elements.length; 78 | if (oldCapacity >= capacity) return; 79 | 80 | // 新容量为旧容量的1.5倍 81 | int newCapacity = oldCapacity + (oldCapacity >> 1); 82 | E[] newElements = (E[]) new Object[newCapacity]; 83 | for (int i = 0; i < size; i++) { 84 | newElements[i] = elements[index(i)]; 85 | } 86 | elements = newElements; 87 | 88 | // 重置front 89 | front = 0; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_1047. 删除字符串中的所有相邻重复项.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | import javax.print.StreamPrintService; 4 | 5 | /** 6 | * 给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。 7 | * 8 | * 在 S 上反复执行重复项删除操作,直到无法继续删除。 9 | * 10 | * 在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。 11 | * 12 | *   13 | * 14 | * 示例: 15 | * 16 | * 输入:"abbaca" 输出:"ca" 解释: 例如,在 "abbaca" 中,我们可以删除 "bb" 17 | * 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 18 | * 可以执行重复项删除操作,所以最后的字符串为 "ca"。   19 | * 20 | * 提示: 21 | * 22 | * 1 <= S.length <= 20000 S 仅由小写英文字母组成。 23 | * 24 | * 来源:力扣(LeetCode) 25 | * 链接:https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * 28 | */ 29 | 30 | /** 31 | * 32 | * 并没有想着使用栈,看到题目的第一个想法就是直接遍历,qaq 33 | * 34 | * 执行用时 : 15 ms , 在所有 Java 提交中击败了 80.24% 的用户 35 | * 36 | * 内存消耗 : 40.3 MB , 在所有 Java提交中击败了7.69% 的用户 37 | * 38 | */ 39 | 40 | class Solution { 41 | public String removeDuplicates(String S) { 42 | char[] array = S.toCharArray(); 43 | StringBuffer string = new StringBuffer(); 44 | for (int i = 0; i < array.length; i++) { 45 | char c = array[i]; 46 | if (string.length() == 0 || string.charAt(string.length() - 1) != c) { 47 | string.append(c); 48 | } else { 49 | string.deleteCharAt(string.length() - 1); 50 | } 51 | } 52 | return string.toString(); 53 | } 54 | 55 | } 56 | 57 | /** 58 | * 官方使用栈的解法 59 | * 60 | * 使用栈去解决这个问题 执行用时 : 29 ms , 在所有 Java 提交中击败了 62.54% 的用户 61 | * 62 | * 内存消耗 : 40.8 MB , 在所有Java 提交中击败了 7.69% 的用户 63 | */ 64 | 65 | class Solution { 66 | public String removeDuplicates(String S) { 67 | char[] array = S.toCharArray(); 68 | Stack stack = new Stack<>(); 69 | for (int i = 0; i < array.length; i++) { 70 | if (stack.isEmpty() || array[i] != stack.peek()) { 71 | stack.push(array[i]); 72 | } else { 73 | stack.pop(); 74 | } 75 | } 76 | StringBuffer str = new StringBuffer(); 77 | for (Character character : stack) { 78 | str.append(character); 79 | } 80 | return str.toString(); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /Top/02-链表/_234_回文链表.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 请判断一个链表是否为回文链表。 4 | * 5 | * 示例 1: 6 | * 7 | * 输入: 1->2 输出: false 示例 2: 8 | * 9 | * 输入: 1->2->2->1 输出: true 进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题? 10 | * 11 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/palindrome-linked-list 12 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 13 | * 14 | * 15 | */ 16 | 17 | // Definition for singly-linked list. 18 | public class ListNode { 19 | int val; 20 | ListNode next; 21 | 22 | ListNode(int x) { 23 | val = x; 24 | } 25 | } 26 | 27 | class Solution { 28 | /** 29 | * 找到前半部分链表的尾节点。 30 | * 31 | * 反转后半部分链表。 32 | * 33 | * 判断是否为回文。 34 | * 35 | * 恢复链表。 36 | * 37 | * 返回结果。 38 | * 39 | */ 40 | public boolean isPalindrome(ListNode head) { 41 | if (head == null || head.next == null) 42 | return true; 43 | if (head.next.next == null) 44 | return head.val == head.next.val; 45 | 46 | // 找到中间节点 47 | ListNode mid = middleNode(head); 48 | 49 | // 翻转右半部分(中间节点的右边部分) 50 | ListNode rHead = reverseList(mid.next); 51 | ListNode lHead = head; 52 | ListNode rOldHead = rHead; 53 | 54 | // 从lHead、rHead出发,判断是否为回文链表 55 | boolean result = true; 56 | while (rHead != null) { 57 | if (lHead.val != rHead.val) { 58 | result = false; 59 | break; 60 | } 61 | rHead = rHead.next; 62 | lHead = lHead.next; 63 | } 64 | 65 | // 恢复右半部分(对右半部分再次翻转) 66 | reverseList(rOldHead); 67 | return result; 68 | 69 | } 70 | 71 | private ListNode middleNode(ListNode head) { 72 | ListNode fast = head; 73 | ListNode slow = head; 74 | while (fast.next != null && fast.next.next != null) { 75 | slow = slow.next; 76 | fast = fast.next.next; 77 | } 78 | return slow; 79 | } 80 | 81 | private reverseList(ListNode head) { 82 | ListNode prev = null, tempNext = null; 83 | while (head != null) { 84 | tempNext = head.next; 85 | head.next = prev; 86 | prev = head; 87 | head = tempNext; 88 | } 89 | return prev; 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /剑指Offer/面试题56_I_数组中数字出现的次数.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。 4 | * 5 | * 请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。 6 | * 7 | * 示例 1: 8 | * 9 | * 输入:nums = [4,1,4,6] 输出:[1,6] 或 [6,1] 10 | * 11 | * 示例 2: 12 | * 13 | * 输入:nums = [1,2,10,4,1,4,3,3] 输出:[2,10] 或 [10,2]   14 | * 15 | * 限制: 16 | * 17 | * 2 <= nums.length <= 10000 18 | * 19 | * 来源:力扣(LeetCode) 20 | * 链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof 21 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 22 | * 23 | * 24 | * 25 | */ 26 | 27 | // 本题和主站 260 是一样的. 除了这个,主站还有 136 和 137,645。 28 | // 首先题干对空间和时间复杂度都有要求 又是直奔题解的一天 29 | class Solution { 30 | public int[] singleNumbers(int[] nums) { 31 | int sum = 0; 32 | // 将数组所有元素进行异或,最后的结果一定是那两个单一数字的异或结果。 33 | // 用示例[4,4,6,1]最后的抑或结果就是 6和1异或的结果 7 34 | for (int i = 0; i < nums.length; i++) { 35 | sum ^= nums[i]; 36 | } 37 | int first = 1; 38 | // 通过与运算找到result第一个不为0的首位,7=>0111,也就是第一位 39 | while ((sum & first) == 0) { 40 | first = first << 1; 41 | } 42 | // first为1,所以我们可以根据数组元素的二进制低位第一位是否为1,将数组分为2类, 43 | // 示例数组可以分为 低位第一位为0:[4,4,6] 低位第一位为1:[1] 44 | // 此时再将两个数组两两异或就可以得到最终结果。 45 | int result[] = new int[2]; 46 | for (int i = 0; i < nums.length; i++) { 47 | // 将数组分类。 48 | if ((nums[i] & first) == 0) { 49 | result[0] ^= nums[i]; 50 | } else { 51 | result[1] ^= nums[i]; 52 | } 53 | } 54 | return result; 55 | } 56 | 57 | public int[] singleNumbers_diy(int[] nums) { 58 | int sum = 0; 59 | for (int num : nums) 60 | sum ^= num; 61 | 62 | int first = 1; 63 | while ((sum & first) == 0) 64 | first = first << 1; 65 | 66 | int[] result = new int[2]; 67 | for (int num : nums) { 68 | if ((num & first) == 0) 69 | result[0] ^= num; 70 | else 71 | result[1] ^= num; 72 | } 73 | return result; 74 | 75 | } 76 | 77 | } 78 | // 作者:SuperCarry 79 | // 链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/solution/liang-liao-wei-yun-suan-yi-huo-shuang-bai-guo-by-1/ 80 | // 来源:力扣(LeetCode) 81 | // 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 -------------------------------------------------------------------------------- /剑指Offer/_面试题13_机器人的运动范围.java: -------------------------------------------------------------------------------- 1 | import java.util.LinkedList; 2 | 3 | /** 4 | * 地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 5 | * 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 6 | * [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子? 7 | * 8 | * 示例 1: 9 | * 10 | * 输入:m = 2, n = 3, k = 1 11 | * 12 | * 输出:3 13 | * 14 | * 示例 2: 15 | * 16 | * 输入:m = 3, n = 1, k = 0 17 | * 18 | * 输出:1 19 | * 20 | * 提示: 21 | * 22 | * 1 <= n,m <= 100 23 | * 24 | * 0 <= k <= 20 25 | * 26 | * 来源:力扣(LeetCode) 27 | * 链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof 28 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 29 | * 30 | * 31 | */ 32 | 33 | class Solution { 34 | int m, n, k; 35 | boolean[][] visited; 36 | 37 | // bfs需要使用到queue 38 | Queue queue; 39 | 40 | public int movingCount(int m, int n, int k) { 41 | this.m = m; 42 | this.n = n; 43 | this.k = k; 44 | visited = new boolean[m][n]; 45 | 46 | // return dfs(0, 0, 0, 0); 47 | return bfs(); 48 | } 49 | 50 | int bfs() { 51 | int resulut = 0; 52 | queue = new LinkedList(); 53 | queue.add(new int[] { 0, 0, 0, 0 }); 54 | 55 | while (!queue.isEmpty()) { 56 | int[] element = queue.remove(); 57 | int i = element[0], j = element[1], si = element[2], sj = element[3]; 58 | if (i >= m || j >= n || si + sj > k || visited[i][j]) 59 | continue; 60 | visited[i][j] = true; 61 | resulut++; 62 | int si_plus = (i + 1) % 10 == 0 ? si - 8 : si + 1; 63 | int sj_plus = (j + 1) % 10 == 0 ? sj - 8 : sj + 1; 64 | queue.add(new int[] { i + 1, j, si_plus, sj }); 65 | queue.add(new int[] { i, j + 1, si, sj_plus }); 66 | 67 | } 68 | return resulut; 69 | } 70 | 71 | /** 72 | * 当前元素在矩阵中的行列索引 i 和 j ,两者的数位和 si, sj 。 73 | */ 74 | int dfs(int i, int j, int si, int sj) { 75 | if (i >= m || j >= n || k < si + sj || visited[i][j]) 76 | return 0; 77 | 78 | visited[i][j] = true; 79 | int si_plus = (i + 1) % 10 == 0 ? si - 8 : si + 1; 80 | int sj_plus = (j + 1) % 10 == 0 ? sj - 8 : sj + 1; 81 | return 1 + dfs(i + 1, j, si_plus, sj) + dfs(i, j + 1, si, sj_plus); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /剑指Offer/_面试题59_II_队列的最大值.java: -------------------------------------------------------------------------------- 1 | import java.util.Deque; 2 | import java.util.LinkedList; 3 | import java.util.Queue; 4 | 5 | /** 6 | * 7 | * 请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 8 | * 的均摊时间复杂度都是O(1)。 9 | * 10 | * 若队列为空,pop_front 和 max_value 需要返回 -1 11 | * 12 | * 示例 1: 13 | * 14 | * 输入: ["MaxQueue","push_back","push_back","max_value","pop_front","max_value"] 15 | * [[],[1],[2],[],[],[]] 输出: [null,null,null,2,1,2] 示例 2: 16 | * 17 | * 输入: ["MaxQueue","pop_front","max_value"] [[],[],[]] 输出: [null,-1,-1]   18 | * 19 | * 限制: 20 | * 21 | * 1 <= push_back,pop_front,max_value的总操作数 <= 10000 1 <= value <= 10^5 22 | * 23 | * 来源:力扣(LeetCode) 24 | * 链接:https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof 25 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 26 | * 27 | */ 28 | 29 | /** 30 | * 31 | * 使用 \mathcal{O}(1)O(1) 32 | * 时间复杂度来获得队列或栈的最大值或者最小值,往往需要使用一个辅助的数据结构实现,具体选用何种数据结构需要在做题过程中总结规律。 33 | * 34 | * 相关题目(实现 \mathcal{O}(1)O(1) 复杂度): 35 | * 36 | * 面试题 03.02. 栈的最小值(难度:⭐⭐)(使用辅助栈) 37 | * 38 | * 146. LRU缓存机制 (难度:⭐⭐⭐⭐)(使用有序字典) 39 | * 40 | * 716. 最大栈(难度:⭐⭐⭐)(使用辅助栈) 41 | * 42 | * 作者:z1m 43 | * 链接:https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof/solution/ru-he-jie-jue-o1-fu-za-du-de-api-she-ji-ti-by-z1m/ 44 | * 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 45 | * 46 | * 47 | */ 48 | 49 | class MaxQueue { 50 | Queue queue; 51 | Deque deque; 52 | 53 | public MaxQueue() { 54 | queue = new LinkedList<>(); 55 | deque = new LinkedList<>(); 56 | } 57 | 58 | public int max_value() { 59 | return deque.isEmpty() ? -1 : deque.peek(); 60 | } 61 | 62 | public void push_back(int value) { 63 | queue.offer(value); 64 | while (!deque.isEmpty() && deque.peekLast() < value) { 65 | deque.pollLast(); 66 | } 67 | deque.offerLast(value); 68 | 69 | } 70 | 71 | public int pop_front() { 72 | if (queue.isEmpty()) 73 | return -1; 74 | 75 | int temp = queue.poll(); 76 | 77 | if (deque.peek().equals(temp)) 78 | deque.poll(); 79 | 80 | return temp; 81 | } 82 | } 83 | 84 | /** 85 | * Your MaxQueue object will be instantiated and called as such: MaxQueue obj = 86 | * new MaxQueue(); int param_1 = obj.max_value(); obj.push_back(value); int 87 | * param_3 = obj.pop_front(); 88 | */ -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_316. 去除重复字母.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | import java.util.HashSet; 3 | import java.util.Stack; 4 | 5 | /** 6 | * _316. 去除重复字母 7 | * 8 | * 给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)。 9 | * 10 | * 示例 1: 11 | * 输入: "bcabc" 输出: "abc" 示例 2: 12 | * 输入: "cbacdcbc" 输出: "acdb"   13 | * 14 | * 注意:该题与 1081 15 | * https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 16 | * 相同 17 | * 18 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/remove-duplicate-letters 19 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 20 | * 21 | */ 22 | 23 | /** 24 | * 25 | * 按照官方使用stack的方式撸了一遍 26 | * 27 | * 代码可以理解,但是自己想不到使用这种方式,对于所谓的贪心算法还是有点迷 28 | * 29 | * TODO:官方给的两种方法都是贪心算法,看完贪心算法以后,还需要回来把另外一种方法看下 30 | * 31 | */ 32 | 33 | 34 | class Solution { 35 | public String removeDuplicateLetters(String s) { 36 | 37 | Stack stack = new Stack<>(); 38 | 39 | // this lets us keep track of what's in our solution in O(1) time 40 | HashSet set = new HashSet<>(); 41 | 42 | // this will let us know if there are any more instances of s[i] left in s 43 | HashMap map = new HashMap<>(); 44 | 45 | for (int i = 0; i < s.length(); i++) { 46 | map.put(s.charAt(i), i); 47 | } 48 | 49 | for (int i = 0; i < s.length(); i++) { 50 | char c = s.charAt(i); 51 | // we can only try to add c if it's not already in our solution 52 | // this is to maintain only one of each character 53 | if (!set.contains(c)) { 54 | // if the last letter in our solution: 55 | // 1. exists 56 | // 2. is greater than c so removing it will make the string smaller 57 | // 3. it's not the last occurrence 58 | // we remove it from the solution to keep the solution optimal 59 | while (!stack.isEmpty() && c < stack.peek() && map.get(stack.peek()) > i) { 60 | set.remove(stack.pop()); 61 | } 62 | set.add(c); 63 | stack.push(c); 64 | } 65 | } 66 | 67 | StringBuffer string = new StringBuffer(); 68 | for (Character character : stack) { 69 | string.append(character); 70 | } 71 | 72 | return string.toString(); 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Top/04-字符串/_572_另一个树的子树.java: -------------------------------------------------------------------------------- 1 | import javax.swing.tree.TreeNode; 2 | 3 | /** 4 | * 5 | * 给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。 6 | 7 | 示例 1: 8 | 给定的树 s: 9 | 10 | 3 11 | / \ 12 | 4 5 13 | / \ 14 | 1 2 15 | 给定的树 t: 16 | 17 | 4 18 | / \ 19 | 1 2 20 | 返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。 21 | 22 | 示例 2: 23 | 给定的树 s: 24 | 25 | 3 26 | / \ 27 | 4 5 28 | / \ 29 | 1 2 30 | / 31 | 0 32 | 给定的树 t: 33 | 34 | 4 35 | / \ 36 | 1 2 37 | 返回 false。 38 | 39 | 来源:力扣(LeetCode) 40 | 链接:https://leetcode-cn.com/problems/subtree-of-another-tree 41 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 42 | * 43 | * 44 | * 45 | */ 46 | 47 | /** 48 | * Definition for a binary tree node. 49 | */ 50 | public class TreeNode { 51 | int val; 52 | TreeNode left; 53 | TreeNode right; 54 | 55 | TreeNode() { 56 | } 57 | 58 | TreeNode(int val) { 59 | this.val = val; 60 | } 61 | 62 | TreeNode(int val, TreeNode left, TreeNode right) { 63 | this.val = val; 64 | this.left = left; 65 | this.right = right; 66 | } 67 | } 68 | 69 | class Solution { 70 | 71 | /** 72 | * 前序遍历 后序遍历 层序遍历(不建议)因为遍历节点不需要兄弟节点,而是遍历子节点 73 | * 74 | * 通过二叉树序列化并通过字符串包含解决 75 | * 76 | * ◼ 非空节点:值 77 | * 78 | * ◼ 空节点也必须要序列化,才能完整地表达唯一的一棵树 79 | * 80 | */ 81 | public boolean isSubtree(TreeNode s, TreeNode t) { 82 | if (s == null || t == null) 83 | return false; 84 | return postSerialize(s).contains((postSerialize(t))); 85 | } 86 | 87 | /** 88 | * 利用后序遍历的方式进行序列化 89 | * 90 | * @param root 91 | * @return 92 | */ 93 | private String postSerialize(TreeNode root) { 94 | StringBuilder sb = new StringBuilder();//如果是前序遍历的话可以初始化的时候使用一个符号 防止误判(12 2 ) 95 | postSerialize(root, sb); 96 | return sb.toString(); 97 | } 98 | 99 | private void postSerialize(TreeNode node, StringBuilder sb) { 100 | 101 | if (node.left == null) { 102 | sb.append("#!"); 103 | } else { 104 | postSerialize(node.left, sb); 105 | } 106 | if (node.right == null) { 107 | sb.append("#!"); 108 | } else { 109 | postSerialize(node.right, sb); 110 | } 111 | sb.append(node.val).append("!");//如果是前序遍历 则放到最前 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /Top/04-字符串/_151_翻转字符串里的单词.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个字符串,逐个翻转字符串中的每个单词。 3 | * 4 | *   5 | * 6 | * 示例 1: 7 | * 8 | * 输入: "the sky is blue" 输出: "blue is sky the" 示例 2: 9 | * 10 | * 输入: "  hello world!  " 输出: "world! hello" 解释: 11 | * 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 示例 3: 12 | * 13 | * 输入: "a good   example" 输出: "example good a" 解释: 14 | * 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。   15 | * 16 | * 说明: 17 | * 18 | * 无空格字符构成一个单词。 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 19 | * 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。   20 | * 21 | * 进阶: 22 | * 23 | * 请选用 C 语言的用户尝试使用 O(1) 额外空间复杂度的原地解法。 24 | * 25 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/reverse-words-in-a-string 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * 28 | */ 29 | 30 | /** 31 | * 说明: 无空格字符构成一个单词 32 | * 33 | * 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括 34 | * 35 | * 如果单词间有多余的空格,将反转后单词间的空格减少到只含一个 36 | * 37 | */ 38 | 39 | class Solution { 40 | public String reverseWords(String s) { 41 | 42 | if (s == null) 43 | return ""; 44 | /** 45 | * 消除多余的空格 46 | */ 47 | char[] chars = s.toCharArray(); 48 | // 字符串的最终有效长度;当前存放字符的位置 49 | int len = 0, cur = 0; 50 | // 前一个字符是否为空格,默认为true代表默认使-1的位置为空格,则字符默认从0开始 51 | boolean space = true; 52 | 53 | for (int i = 0; i < chars.length; i++) { 54 | if (chars[i] != ' ') { 55 | chars[cur++] = chars[i]; 56 | space = false; 57 | } else if (space == false) { 58 | chars[cur++] = ' '; 59 | space = true; 60 | } 61 | } 62 | len = space ? (cur - 1) : cur; 63 | if (len <= 0) 64 | return ""; 65 | 66 | // 对整一个有效字符串进行逆序 67 | reverse(chars, 0, len); 68 | 69 | int prevSapceIdx = -1; 70 | for (int i = 0; i < len; i++) { 71 | if (chars[i] != ' ') 72 | continue; 73 | // i是空格字符的位置 74 | reverse(chars, prevSapceIdx + 1, i); 75 | prevSapceIdx = i; 76 | } 77 | // 翻转最后一个单词 78 | reverse(chars, prevSapceIdx + 1, len); 79 | return new String(chars, 0, len); 80 | 81 | } 82 | 83 | /** 84 | * 将[li, ri)范围内的字符串进行逆序 85 | */ 86 | private static void reverse(char[] chars, int li, int ri) { 87 | ri--; 88 | while (li < ri) { 89 | char tmp = chars[li]; 90 | chars[li] = chars[ri]; 91 | chars[ri] = tmp; 92 | li++; 93 | ri--; 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /08-动态规划/src/com/dp/LIS.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 最长上升子序列 给定一个无序的整数数组 4 | * 5 | * 找到其中最长上升子序列的长度,子序列不需要连续 6 | */ 7 | public class LIS { 8 | // [1,3,6,7,9,4,10,5,6] 9 | 10 | public static void main(String[] args) { 11 | System.out.println(lengthOfLIS(new int[] { 1, 3, 6, 7, 9, 4, 10, 5, 6 })); 12 | System.out.println(lengthOfLIS_pile0(new int[] { 1, 3, 6, 7, 9, 4, 10, 5, 6 })); 13 | System.out.println(lengthOfLIS_pile1(new int[] { 1, 3, 6, 7, 9, 4, 10, 5, 6 })); 14 | 15 | } 16 | 17 | /** 18 | * 动态规划 19 | * 20 | * dp[i]表示以第i个元素结尾的最长子序列,计算该dp[i],需要遍历i之前的所有的元素,并与当前元素进行比较 21 | * 22 | * 求出所有的情况的子序列以后,求出最大值 23 | */ 24 | static int lengthOfLIS(int[] nums) { 25 | if (nums == null || nums.length == 0) 26 | return 0; 27 | int[] dp = new int[nums.length]; 28 | int max = dp[0] = 1; 29 | for (int i = 1; i < dp.length; i++) { 30 | dp[i] = 1; 31 | for (int j = 0; j < i; j++) { 32 | if (nums[i] <= nums[j]) 33 | continue; 34 | dp[i] = Math.max(dp[i], dp[j] + 1); 35 | } 36 | // System.out.println("dp[" + i + "]:" + dp[i]); 37 | max = Math.max(dp[i], max); 38 | } 39 | return max; 40 | } 41 | 42 | /** 43 | * 把每个数字看做是一张扑克牌,从左到右按顺序处理每一个扑克牌 44 | * 45 | * 将它压在(从左边数过来)第一个牌顶 ≥ 它的牌堆上面 46 | * 47 | * 如果找不到牌顶 ≥ 它的牌堆,就在最右边新建一个牌堆,将它放入这个新牌堆中 48 | * 49 | * 当处理完所有牌,最终牌堆的数量就是最长上升子序列的长度 50 | */ 51 | static int lengthOfLIS_pile0(int[] nums) { 52 | int len = 0; // 牌堆的数量 53 | int[] top = new int[nums.length]; // 牌顶数组 54 | int idx; // 当前所遍历的牌堆的索引 55 | for (int num : nums) { 56 | idx = 0; 57 | while (idx < len) { 58 | if (top[idx] >= num) { 59 | // 当找到当前数值所在位置,退出循环 60 | top[idx] = num; 61 | break; 62 | } 63 | // 没有新建一个牌堆,需要将idx往后挪一位 64 | idx++; 65 | } 66 | // 67 | if (idx == len) { 68 | len++; 69 | top[idx] = num; 70 | } 71 | 72 | } 73 | return len; 74 | } 75 | 76 | /** 77 | * 对牌顶数组的操作(遍历数组并查找合适的位置)可以是用二分法优化 78 | */ 79 | static int lengthOfLIS_pile1(int[] nums) { 80 | int len = 0; // 牌堆的数量 81 | int[] top = new int[nums.length]; // 牌顶数组 82 | for (int num : nums) { 83 | int begin = 0 ,end = len; 84 | while (begin < end) { 85 | int mid = (begin + end) >> 1; 86 | if (num <= top[mid]) { 87 | end = mid; 88 | } else { 89 | begin = mid + 1; 90 | } 91 | } 92 | // 覆盖牌顶 93 | top[begin] = num; 94 | 95 | if(begin == len) len++; 96 | 97 | } 98 | return len; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Leetcode/Array&String/_989.数组形式的整数加法.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 对于非负整数 X 而言,X 的数组形式是每位数字按从左到右的顺序形成的数组。例如,如果 X = 1231,那么其数组形式为 [1,2,3,1]。 3 | * 4 | * 给定非负整数 X 的数组形式 A,返回整数 X+K 的数组形式。 5 | * 6 | * 7 | * 示例 1: 8 | * 9 | * 输入:A = [1,2,0,0], K = 34 输出:[1,2,3,4] 解释:1200 + 34 = 1234 10 | * 11 | * 示例 2: 12 | * 13 | * 输入:A = [2,7,4], K = 181 输出:[4,5,5] 解释:274 + 181 = 455 14 | * 15 | * 示例 3: 16 | * 17 | * 输入:A = [2,1,5], K = 806 输出:[1,0,2,1] 解释:215 + 806 = 1021 18 | * 19 | * 示例 4: 20 | * 21 | * 输入:A = [9,9,9,9,9,9,9,9,9,9], K = 1 输出:[1,0,0,0,0,0,0,0,0,0,0] 解释:9999999999 22 | * + 1 = 10000000000   23 | * 24 | * 提示: 25 | * 26 | * 1 <= A.length <= 10000 0 <= A[i] <= 9 0 <= K <= 10000 如果 A.length > 1,那么 A[0] 27 | * != 0 28 | * 29 | * 来源:力扣(LeetCode) 30 | * 链接:https://leetcode-cn.com/problems/add-to-array-form-of-integer 31 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 32 | * 33 | * 来源:力扣(LeetCode) 34 | * 链接:https://leetcode-cn.com/problems/add-to-array-form-of-integer 35 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 36 | * 37 | * 38 | */ 39 | 40 | /** 41 | * 42 | * 链接:https://leetcode-cn.com/problems/add-to-array-form-of-integer/solution/shu-zu-xing-shi-de-zheng-shu-jia-fa-by-leetcode/ 43 | * 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 44 | * 45 | * 下方解法来自官方题解的评论区: 46 | * K为大数时,题解有溢出风险(但题中已交代K的范围,所以此题可行),所以应当将K按位转化为数组。 47 | * 48 | */ 49 | 50 | class Solution { 51 | public List addToArrayForm(int[] A, int K) { 52 | 53 | //得出K的位数 54 | int lenB = 0; 55 | while (K >= Math.pow(10, lenB)) { 56 | lenB++; 57 | } 58 | 59 | //将k转化为数组 60 | int[] B = new int[lenB]; 61 | while (lenB > 0) { 62 | B[--lenB] = K % 10; 63 | K = K / 10; 64 | } 65 | 66 | Integer i = A.length - 1; 67 | Integer j = B.length - 1; 68 | int n = i > j ? i : j; //防止数组越界,保证相加为的最大index 69 | int[] ansArray = new int[n + 1]; 70 | int num = 0; 71 | while (i >= 0 && j >= 0) { 72 | ansArray[n--] = (A[i] + B[j] + num) % 10; 73 | num = (A[i--] + B[j--] + num) / 10; 74 | } 75 | while (i >= 0) { 76 | ansArray[n--] = (A[i] + num) % 10; 77 | num = (A[i--] + num) / 10; 78 | } 79 | while (j >= 0) { 80 | ansArray[n--] = (B[j] + num) % 10; 81 | num = (B[j--] + num) / 10; 82 | } 83 | List ansList = new ArrayList<>(); 84 | if (num != 0) 85 | ansList.add(num); 86 | for (int val : ansArray) 87 | ansList.add(val); 88 | return ansList; 89 | } 90 | 91 | } -------------------------------------------------------------------------------- /Top/03-栈&队列/_739_每日温度.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | /** 4 | * 根据每日 气温 列表,请重新生成一个列表,对应位置的输出是需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。 5 | * 6 | * 例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 7 | * 2, 1, 1, 0, 0]。 8 | * 9 | * 提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。 10 | * 11 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/daily-temperatures 12 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 13 | * 14 | */ 15 | class Solution { 16 | public int[] dailyTemperatures(int[] T) { 17 | return dailyTemperatures_stack(T); 18 | } 19 | 20 | static int[] dailyTemperatures_stack(int[] T) { 21 | 22 | if (T.length == 0) 23 | return T; 24 | 25 | Stack stack = new Stack<>(); 26 | int[] result = new int[T.length]; 27 | for (int i = 0; i < result.length; i++) { 28 | result[i] = 0; 29 | } 30 | for (int i = 0; i < T.length; i++) { 31 | while (!stack.isEmpty() && T[i] > T[stack.peek()]) { 32 | int idx = stack.pop(); 33 | result[idx] = i - idx; 34 | } 35 | stack.push(i); 36 | } 37 | return result; 38 | } 39 | 40 | // 倒推法 41 | 42 | public int[] dailyTemperatures_backward0(int[] T) { 43 | 44 | if (T.length == 0) 45 | return T; 46 | 47 | int[] values = new int[T.length]; 48 | 49 | for (int i = T.length - 2; i >= 0; i--) { 50 | int j = i + 1; 51 | while (true) { 52 | if (T[i] < T[j]) { 53 | values[i] = j - i; 54 | break; 55 | } else if (values[j] == 0) { 56 | values[i] = 0; 57 | break; 58 | } else if (T[i] == T[j]) { 59 | values[i] = values[j] + j - i; 60 | break; 61 | } else { 62 | j = j + values[j]; 63 | } 64 | } 65 | } 66 | return values; 67 | } 68 | 69 | public int[] dailyTemperatures_backward1(int[] T) { 70 | int[] values = new int[T.length]; 71 | for (int i = T.length - 2; i >= 0; i--) { 72 | int j = i + 1; 73 | while (true) { 74 | if (T[i] < T[j]) { 75 | values[i] = j - i; 76 | break; 77 | } else if (values[j] == 0) { 78 | values[i] = 0; 79 | break; 80 | } 81 | // 当T[i] == T[j]的时候 82 | j = j + values[j]; 83 | } 84 | } 85 | return values; 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /Top/06-二叉树/_333_最大BST子树.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个二叉树,找到其中最大的二叉搜索树(BST)子树,其中最大指的是子树节点数最多的 3 | * 4 | * 注意: 5 | * 6 | * 子树必须包含其所有后代 7 | * 8 | * 9 | */ 10 | 11 | class Solution { 12 | 13 | public int largestBSTSubtree(TreeNode root) { 14 | return (root == null) ? 0 : getInfo(root).size; 15 | } 16 | 17 | /** 18 | * 返回以root为根节点的二叉树的最大BST子树信息 19 | * 20 | * @param root 21 | * @return 22 | */ 23 | private Info getInfo(TreeNode root) { 24 | if (root == null) 25 | return null; 26 | 27 | // 自底向上的后序遍历 28 | 29 | // li(left info):左子树的最大BST子树信息 30 | Info li = getInfo(root.left); 31 | 32 | // ri(right info):右子树的最大BST子树信息 33 | Info ri = getInfo(root.right); 34 | 35 | /* 36 | * 有4种情况,以root为根节点的二叉树就是一棵BST,最大BST子树就是其本身 ① li != null && ri != null && li.root 37 | * == root.left && root.val > li.max && ri.root == root.right && root.val < 38 | * ri.min 39 | * 40 | * ② li != null && ri == null && li.root == root.left && root.val > li.max 41 | * 42 | * ③ li == null && ri != null && ri.ro ot == root.right && root.val < ri.min 43 | * 44 | * ④ li == null && ri == null 45 | */ 46 | int leftBstSize = -1, rightBstSize = -1, max = root.val, min = root.val; 47 | if (li == null) { 48 | leftBstSize = 0; 49 | } else if (li.root == root.left && root.val > li.max) { 50 | leftBstSize = li.size; 51 | min = li.min; 52 | } 53 | 54 | if (ri == null) { 55 | rightBstSize = 0; 56 | } else if (ri.root == root.right && root.val < ri.min) { 57 | rightBstSize = ri.size; 58 | max = ri.max; 59 | } 60 | // 以root为根节点的二叉树是bst 61 | if (leftBstSize >= 0 && rightBstSize >= 0) { 62 | return new Info(root, 1 + leftBstSize + rightBstSize, max, min); 63 | } 64 | 65 | // 以root为根节点的二叉树并不是BST 66 | 67 | // 返回最大BST子树的节点数量较多的那个Info 68 | if (li != null && ri != null) 69 | return (li.size > ri.size) ? li : ri; 70 | 71 | // 返回li、ri中不为null的那个Info 72 | return (li != null) ? li : ri; 73 | } 74 | 75 | /** 76 | * 最大BST子树的信息 77 | */ 78 | private static class Info { 79 | /** 根节点 */ 80 | public TreeNode root; 81 | /** 节点总数 */ 82 | public int size; 83 | /** 最大值 */ 84 | public int max; 85 | /** 最小值 */ 86 | public int min; 87 | 88 | public Info(TreeNode root, int size, int max, int min) { 89 | this.root = root; 90 | this.size = size; 91 | this.max = max; 92 | this.min = min; 93 | } 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/_150. 逆波兰表达式求值.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | /** 4 | * 根据逆波兰表示法,求表达式的值。 5 | * 6 | * 有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 7 | * 8 | * 说明: 9 | * 10 | * 整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。 示例 1: 11 | * 12 | * 输入: ["2", "1", "+", "3", "*"] 输出: 9 解释: ((2 + 1) * 3) = 9 示例 2: 13 | * 14 | * 输入: ["4", "13", "5", "/", "+"] 输出: 6 解释: (4 + (13 / 5)) = 6 示例 3: 15 | * 16 | * 输入: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"] 输出: 17 | * 22 解释: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 = ((10 * (6 / (12 * -11))) + 18 | * 17) + 5 = ((10 * (6 / -132)) + 17) + 5 = ((10 * 0) + 17) + 5 = (0 + 17) + 5 = 19 | * 17 + 5 = 22 20 | * 21 | * 来源:力扣(LeetCode) 22 | * 链接:https://leetcode-cn.com/problems/evaluate-reverse-polish-notation 23 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | * 25 | */ 26 | 27 | /** 28 | * 该题主要考察的是逆序表达式的运算方式 29 | * 30 | * 唯一需要注意的是 num1 和 num2 的顺序不要搞错了 先pop出来的是num2 ,第二次pop出来的是num1 ,然后 num1 <运算符> num2 31 | * 32 | * 后缀表达式的计算 https://blog.csdn.net/qq_21515253/article/details/96484567 33 | */ 34 | class Solution { 35 | public int evalRPN(String[] tokens) { 36 | if (tokens.length == 0) 37 | return 0; 38 | Stack stack = new Stack<>(); 39 | for (String string : tokens) { 40 | switch (string) { 41 | case "+": 42 | // Integer num2 = stack.pop(); 43 | // Integer num1 = stack.pop(); 44 | // stack.push(num1 + num2); 45 | stack.push(stack.pop() + stack.pop()); 46 | break; 47 | case "-": 48 | // Integer num2 = stack.pop(); 49 | // Integer num1 = stack.pop(); 50 | // stack.push(num1 - num2); 51 | stack.push(-(stack.pop() - stack.pop())); 52 | break; 53 | case "*": 54 | // Integer num2 = stack.pop(); 55 | // Integer num1 = stack.pop(); 56 | // stack.push(num1 * num2); 57 | stack.push(stack.pop() * stack.pop()); 58 | break; 59 | case "/": 60 | // Integer num2 = stack.pop(); 61 | // Integer num1 = stack.pop(); 62 | // stack.push(num1 / num2); 63 | Integer num2 = stack.pop(); 64 | Integer num1 = stack.pop(); 65 | stack.push(num1 / num2); 66 | break; 67 | 68 | default: 69 | stack.push(Integer.parseInt(string)); 70 | break; 71 | } 72 | } 73 | return stack.pop().intValue(); 74 | 75 | } 76 | } -------------------------------------------------------------------------------- /Leetcode/Stack&Queue/广度优先搜索(BFS)模板.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 广度优先搜索(BFS) 4 | 5 | ``广度优先搜索(BFS)``的一个常见应用是找出从根结点到目标结点的``最短路径``,当然也可以完成``遍历`` 6 | 7 | 8 | ### 那么为什么 BFS 算法中可以应用队列中呢? 9 | 10 | 我们首先将根结点排入队列。然后在每一轮中,我们逐个处理已经在队列中的结点,并将所有邻居添加到队列中。值得注意的是,新添加的节点不会立即遍历,而是在下一轮中处理。结点的处理顺序与它们添加到队列的顺序是完全相同的顺序,即先进先出**(FIFO)**。 11 | 这就是我们在 BFS 中使用队列的原因。与**树的层序遍历**类似,越是接近根结点的结点将越早地遍历。所以BFS可以用来找到根节点到目标节点的最短距离 12 | 13 | 14 | 15 | 16 | ### 模板 I 17 | 18 | ```java 19 | /** 20 | * Return the length of the shortest path between root and target node. 21 | */ 22 | int BFS(Node root, Node target) { 23 | Queue queue; // store all nodes which are waiting to be processed 24 | int step = 0; // number of steps neeeded from root to current node 25 | // initialize 26 | add root to queue; 27 | // BFS 28 | while (queue is not empty) { 29 | step = step + 1; 30 | // iterate the nodes which are already in the queue 31 | int size = queue.size(); 32 | for (int i = 0; i < size; ++i) { 33 | Node cur = the first node in queue; 34 | return step if cur is target; 35 | for (Node next : the neighbors of cur) { 36 | add next to queue; 37 | } 38 | remove the first node from queue; 39 | } 40 | } 41 | return -1; // there is no path from root to target 42 | } 43 | ``` 44 | 45 | * 如代码所示,在每一轮中,队列中的结点是等待处理的结点。 46 | * 在每个更外一层的 while 循环之后,我们距离根结点更远一步。变量 step 指示从根结点到我们正在访问的当前结点的距离。 47 | 48 | 49 | ### 模板 II 50 | 51 | 有时,确保我们永远不会访问一个结点两次很重要。否则,我们可能陷入无限循环。如果是这样,我们可以在上面的代码中添加一个哈希集来解决这个问题。这是修改后的伪代码: 52 | 53 | ```java 54 | /** 55 | * Return the length of the shortest path between root and target node. 56 | */ 57 | int BFS(Node root, Node target) { 58 | Queue queue; // store all nodes which are waiting to be processed 59 | Set used; // store all the used nodes 60 | int step = 0; // number of steps neeeded from root to current node 61 | // initialize 62 | add root to queue; 63 | add root to used; 64 | // BFS 65 | while (queue is not empty) { 66 | step = step + 1; 67 | // iterate the nodes which are already in the queue 68 | int size = queue.size(); 69 | for (int i = 0; i < size; ++i) { 70 | Node cur = the first node in queue; 71 | return step if cur is target; 72 | for (Node next : the neighbors of cur) { 73 | if (next is not in used) { 74 | add next to queue; 75 | add next to used; 76 | } 77 | } 78 | remove the first node from queue; 79 | } 80 | } 81 | return -1; // there is no path from root to target 82 | } 83 | 84 | ``` 85 | 86 | 有两种情况你不需要使用哈希集: 87 | * 你完全确定没有循环,例如,在树遍历中; 88 | * 你确实希望多次将结点添加到队列中。 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /Top/03-栈&队列/_239_滑动窗口最大值.java: -------------------------------------------------------------------------------- 1 | import java.util.Deque; 2 | import java.util.LinkedList; 3 | 4 | /** 5 | * 6 | * 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 7 | * 8 | * 返回滑动窗口中的最大值。 9 | * 10 | *   11 | * 12 | * 进阶: 13 | * 14 | * 你能在线性时间复杂度内解决此题吗? 15 | * 16 | *   17 | * 18 | * 示例: 19 | * 20 | * 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 21 | * 22 | * 输出: [3,3,5,5,6,7] 23 | * 24 | * 解释: 25 | * 26 | * 滑动窗口的位置 最大值 27 | * 28 | * --------------- ----- 29 | * 30 | * [1 3 -1] -3 5 3 6 7 3 31 | * 32 | * 1 [3 -1 -3] 5 3 6 7 3 33 | * 34 | * 1 3 [-1 -3 5] 3 6 7 5 35 | * 36 | * 1 3 -1 [-3 5 3] 6 7 5 37 | * 38 | * 1 3 -1 -3 [5 3 6] 7 6 39 | * 40 | * 1 3 -1 -3 5 [3 6 7] 7 41 | * 42 | * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/sliding-window-maximum 43 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 44 | * 45 | * 提示: 46 | * 47 | * 1 <= nums.length <= 10^5 48 | * 49 | * -10^4 <= nums[i] <= 10^4 50 | * 51 | * 1 <= k <= nums.length 52 | * 53 | */ 54 | class Solution { 55 | public int[] maxSlidingWindow(int[] nums, int k) { 56 | if (nums == null || nums.length == 0 || k < 1) 57 | return new int[0]; 58 | if (k == 1) 59 | return nums; 60 | return maxSlidingWindow_doublePointer(nums, k); 61 | } 62 | 63 | static int[] maxSlidingWindow_doublePointer(int[] nums, int k) { 64 | 65 | int[] maxes = new int[nums.length - k + 1]; 66 | 67 | int maxIdx = 0; 68 | for (int i = 0; i < k; i++) { 69 | if (nums[i] > nums[maxIdx]) 70 | maxIdx = i; 71 | } 72 | int ri = 0; 73 | for (int li = 0; li < maxes.length; li++) { 74 | ri = li + k - 1; 75 | if (maxIdx < li) { 76 | maxIdx = li; 77 | for (int i = li; i <= ri; i++) { 78 | if (nums[i] > nums[maxIdx]) 79 | maxIdx = i; 80 | } 81 | } 82 | if (nums[ri] >= nums[maxIdx]) 83 | maxIdx = ri; 84 | maxes[li] = nums[maxIdx]; 85 | } 86 | return maxes; 87 | } 88 | 89 | /** 90 | * 是用双端队列解决 91 | */ 92 | 93 | static int[] maxSlidingWindow_deque(int[] nums, int k) { 94 | int[] maxes = new int[nums.length - k + 1]; 95 | Deque deque = new LinkedList<>(); 96 | 97 | int li = 0; 98 | for (int ri = 0; ri < nums.length; ri++) { 99 | 100 | while (!deque.isEmpty() && nums[ri] >= nums[deque.peekLast()]) 101 | deque.pollLast(); 102 | 103 | deque.offerLast(ri); 104 | 105 | li = ri - k + 1; 106 | 107 | if (li < 0) 108 | continue; 109 | 110 | if (deque.peekFirst() < li) 111 | deque.pollFirst(); 112 | 113 | maxes[li] = nums[deque.peekFirst()]; 114 | } 115 | return maxes; 116 | 117 | } 118 | } -------------------------------------------------------------------------------- /04-递归/src/com/recursion/Fib.java: -------------------------------------------------------------------------------- 1 | package com.recursion; 2 | 3 | public class Fib { 4 | public static void main(String[] args) { 5 | Fib fib = new Fib(); 6 | int n = 30; 7 | Times.test("fib0", () -> { 8 | System.out.println(fib.fib0(n)); 9 | }); 10 | Times.test("fib1", () -> { 11 | System.out.println(fib.fib1(n)); 12 | }); 13 | Times.test("fib2", () -> { 14 | System.out.println(fib.fib2(n)); 15 | }); 16 | Times.test("fib3", () -> { 17 | System.out.println(fib.fib3(n)); 18 | }); 19 | Times.test("fib4", () -> { 20 | System.out.println(fib.fib4(n)); 21 | }); 22 | 23 | } 24 | 25 | int fib0(int n) { 26 | if (n <= 2) 27 | return 1; 28 | return fib0(n - 1) + fib0(n - 2); 29 | } 30 | 31 | // 使用记忆数组对计算过的值直接获取 32 | int fib1(int n) { 33 | if (n <= 2) 34 | return 1; 35 | int[] visited = new int[n + 1]; 36 | // 切记需要对记忆数组,对应的递归集进行初始化 37 | visited[1] = visited[2] = 1; 38 | return fib1(n, visited); 39 | } 40 | 41 | int fib1(int n, int[] visited) { 42 | if (visited[n] == 0) { 43 | visited[n] = fib1(n - 1, visited) + fib1(n - 2, visited); 44 | } 45 | return visited[n]; 46 | } 47 | 48 | // 递归转为非递归(但并不是所有的递归都可以转为非递归) 49 | int fib2(int n) { 50 | if (n <= 2) 51 | return 1; 52 | int[] visited = new int[n + 1]; 53 | visited[1] = visited[2] = 1; 54 | for (int i = 3; i <= n; i++) 55 | visited[i] = visited[i - 1] + visited[2]; 56 | return visited[n]; 57 | } 58 | 59 | // fib2 array的大部分空间只是临时使用,真正对我们有用的其实是最后一个元素,针对此进行优化 60 | int fib3(int n) { 61 | if (n <= 2) 62 | return 1; 63 | int[] visited = new int[2]; 64 | visited[0] = visited[1] = 1; 65 | for (int i = 3; i <= n; i++) 66 | visited[i % 2] = visited[(i - 1) % 2] + visited[(i - 2) % 2]; 67 | return visited[n % 2]; 68 | } 69 | 70 | // fib3 中针对数组进行了优化,当然还有下面的写法 71 | int fib4(int n) { 72 | if (n <= 2) 73 | return 1; 74 | int first = 1, second = 1, sum; 75 | for (int i = 3; i <= n; i++) { 76 | sum = first + second; 77 | first = second; 78 | second = sum; 79 | } 80 | return second; 81 | } 82 | 83 | // 使用动态规划求解 84 | int fib5(int n) { 85 | if (n <= 2) 86 | return 1; 87 | int[] dp = new int[n + 1]; 88 | dp[1] = dp[2] = 1; 89 | for (int i = 3; i <= n; i++) 90 | dp[i] = dp[i - 1] + dp[i - 2]; 91 | return dp[n]; 92 | } 93 | 94 | // 看到一个大佬的算法,可能需要慢慢理解,处理了递归基,省去了判断 95 | int fib6(int n) { 96 | int a = 0, b = 1, sum; 97 | for (int i = 0; i < n; i++) { 98 | sum = a + b; 99 | a = b; 100 | b = sum; 101 | } 102 | return a; 103 | } 104 | } -------------------------------------------------------------------------------- /00.数据结构/src/circle/CircleDeque.java: -------------------------------------------------------------------------------- 1 | package circle; 2 | 3 | @SuppressWarnings("unchecked") 4 | public class CircleDeque { 5 | private int front; 6 | private int size; 7 | private E[] elements; 8 | private static final int DEFAULT_CAPACITY = 10; 9 | 10 | public CircleDeque() { 11 | elements = (E[]) new Object[DEFAULT_CAPACITY]; 12 | } 13 | 14 | public int size() { 15 | return size; 16 | } 17 | 18 | public boolean isEmpty() { 19 | return size == 0; 20 | } 21 | 22 | public void clear() { 23 | for (int i = 0; i < size; i++) { 24 | elements[index(i)] = null; 25 | } 26 | front = 0; 27 | size = 0; 28 | } 29 | 30 | /** 31 | * 从尾部入队 32 | * @param element 33 | */ 34 | public void enQueueRear(E element) { 35 | ensureCapacity(size + 1); 36 | 37 | elements[index(size)] = element; 38 | size++; 39 | } 40 | 41 | /** 42 | * 从头部出队 43 | * @param element 44 | */ 45 | public E deQueueFront() { 46 | E frontElement = elements[front]; 47 | elements[front] = null; 48 | front = index(1); 49 | size--; 50 | return frontElement; 51 | } 52 | 53 | /** 54 | * 从头部入队 55 | * @param element 56 | */ 57 | public void enQueueFront(E element) { 58 | ensureCapacity(size + 1); 59 | 60 | front = index(-1); 61 | elements[front] = element; 62 | size++; 63 | } 64 | 65 | /** 66 | * 从尾部出队 67 | * @param element 68 | */ 69 | public E deQueueRear() { 70 | int rearIndex = index(size - 1); 71 | E rear = elements[rearIndex]; 72 | elements[rearIndex] = null; 73 | size--; 74 | return rear; 75 | } 76 | 77 | public E front() { 78 | return elements[front]; 79 | } 80 | 81 | public E rear() { 82 | return elements[index(size - 1)]; 83 | } 84 | 85 | @Override 86 | public String toString() { 87 | StringBuilder string = new StringBuilder(); 88 | string.append("capcacity=").append(elements.length) 89 | .append(" size=").append(size) 90 | .append(" front=").append(front) 91 | .append(", ["); 92 | for (int i = 0; i < elements.length; i++) { 93 | if (i != 0) { 94 | string.append(", "); 95 | } 96 | 97 | string.append(elements[i]); 98 | } 99 | string.append("]"); 100 | return string.toString(); 101 | } 102 | 103 | private int index(int index) { 104 | index += front; 105 | if (index < 0) { 106 | return index + elements.length; 107 | } 108 | return index - (index >= elements.length ? elements.length : 0); 109 | } 110 | 111 | /** 112 | * 保证要有capacity的容量 113 | * @param capacity 114 | */ 115 | private void ensureCapacity(int capacity) { 116 | int oldCapacity = elements.length; 117 | if (oldCapacity >= capacity) return; 118 | 119 | // 新容量为旧容量的1.5倍 120 | int newCapacity = oldCapacity + (oldCapacity >> 1); 121 | E[] newElements = (E[]) new Object[newCapacity]; 122 | for (int i = 0; i < size; i++) { 123 | newElements[i] = elements[index(i)]; 124 | } 125 | elements = newElements; 126 | 127 | // 重置front 128 | front = 0; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /01-排序/src/com/sort/Sort.java: -------------------------------------------------------------------------------- 1 | package com.sort; 2 | import java.text.DecimalFormat; 3 | import com.Student; 4 | 5 | @SuppressWarnings("unchecked") 6 | public abstract class Sort> implements Comparable> { 7 | protected T[] array; 8 | private int cmpCount; 9 | private int swapCount; 10 | private long time; 11 | private DecimalFormat fmt = new DecimalFormat("#.00"); 12 | 13 | public void sort(T[] array) { 14 | if (array == null || array.length < 2) 15 | return; 16 | 17 | this.array = array; 18 | 19 | long begin = System.currentTimeMillis(); 20 | sort(); 21 | time = System.currentTimeMillis() - begin; 22 | } 23 | 24 | @Override 25 | public int compareTo(Sort o) { 26 | int result = (int) (time - o.time); 27 | if (result != 0) 28 | return result; 29 | 30 | result = cmpCount - o.cmpCount; 31 | if (result != 0) 32 | return result; 33 | 34 | return swapCount - o.swapCount; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | String timeStr = "耗时:" + (time / 1000.0) + "s(" + time + "ms)"; 40 | String compareCountStr = "比较:" + numberString(cmpCount); 41 | String swapCountStr = "交换:" + numberString(swapCount); 42 | String stableStr = "稳定性:" + isStable(); 43 | return "【" + getClass().getSimpleName() + "】\n" 44 | + stableStr + " \t" 45 | + timeStr + " \t" 46 | + compareCountStr + "\t " 47 | + swapCountStr + "\n" 48 | + "------------------------------------------------------------------"; 49 | } 50 | 51 | protected abstract void sort(); 52 | 53 | /* 54 | * 返回值等于0,代表 array[i1] == array[i2] 返回值小于0,代表 array[i1] < array[i2] 返回值大于0,代表 55 | * array[i1] > array[i2] 56 | */ 57 | protected int cmp(int i1, int i2) { 58 | cmpCount++; 59 | return array[i1].compareTo(array[i2]); 60 | } 61 | 62 | protected int cmp(T v1, T v2) { 63 | cmpCount++; 64 | return v1.compareTo(v2); 65 | } 66 | 67 | protected void swap(int i1, int i2) { 68 | swapCount++; 69 | T tmp = array[i1]; 70 | array[i1] = array[i2]; 71 | array[i2] = tmp; 72 | } 73 | 74 | 75 | 76 | private String numberString(int number) { 77 | if (number < 10000) return "" + number; 78 | 79 | if (number < 100000000) return fmt.format(number / 10000.0) + "万"; 80 | return fmt.format(number / 100000000.0) + "亿"; 81 | } 82 | 83 | private boolean isStable() { 84 | // if (this instanceof RadixSort) return true; 85 | // if (this instanceof CountingSort) return true; 86 | // if (this instanceof ShellSort) return false; 87 | // if (this instanceof SelectionSort) return false; 88 | Student[] students = new Student[20]; 89 | for (int i = 0; i < students.length; i++) { 90 | students[i] = new Student(i * 10, 10); 91 | } 92 | sort((T[]) students); 93 | for (int i = 1; i < students.length; i++) { 94 | int score = students[i].score; 95 | int prevScore = students[i - 1].score; 96 | if (score != prevScore + 10) return false; 97 | } 98 | return true; 99 | } 100 | 101 | } -------------------------------------------------------------------------------- /00.数据结构/src/Main.java: -------------------------------------------------------------------------------- 1 | import circle.CircleDeque; 2 | import circle.CircleQueue; 3 | 4 | public class Main { 5 | 6 | public static void main(String[] args) { 7 | 8 | testStack(); 9 | testQueue(); 10 | testDeque(); 11 | testCircleQueue(); 12 | testCircleDeque(); 13 | 14 | } 15 | 16 | static void testStack() { 17 | Stack stack = new Stack<>(); 18 | stack.push(11); 19 | stack.push(22); 20 | stack.push(33); 21 | stack.push(44); 22 | System.out.println("\n************************testStack************************\n"); 23 | 24 | while (!stack.isEmpty()) { 25 | System.out.println(stack.pop()); 26 | } 27 | } 28 | 29 | static void testQueue() { 30 | Queue queue = new Queue<>(); 31 | queue.enQueue(11); 32 | queue.enQueue(22); 33 | queue.enQueue(33); 34 | queue.enQueue(44); 35 | System.out.println("\n************************testQueue************************\n"); 36 | 37 | while (!queue.isEmpty()) { 38 | System.out.println(queue.deQueue()); 39 | } 40 | } 41 | 42 | static void testDeque() { 43 | 44 | Deque queue = new Deque<>(); 45 | queue.enQueueFront(11); 46 | queue.enQueueFront(22); 47 | queue.enQueueRear(33); 48 | queue.enQueueRear(44); 49 | System.out.println("\n************************testDeque************************\n"); 50 | 51 | /* 尾 44 33 11 22 头 */ 52 | while (!queue.isEmpty()) { 53 | System.out.println(queue.deQueueRear()); 54 | } 55 | } 56 | 57 | static void testCircleQueue() { 58 | CircleQueue queue = new CircleQueue(); 59 | // 0 1 2 3 4 5 6 7 8 9 60 | for (int i = 0; i < 10; i++) { 61 | queue.enQueue(i); 62 | } 63 | // null null null null null 5 6 7 8 9 64 | for (int i = 0; i < 5; i++) { 65 | queue.deQueue(); 66 | } 67 | // 15 16 17 18 19 5 6 7 8 9 68 | for (int i = 15; i < 20; i++) { 69 | queue.enQueue(i); 70 | } 71 | 72 | System.out.println("\n************************testCircleQueue************************\n"); 73 | 74 | while (!queue.isEmpty()) { 75 | System.out.println(queue.deQueue()); 76 | } 77 | System.out.println(queue); 78 | } 79 | 80 | static void testCircleDeque() { 81 | CircleDeque queue = new CircleDeque<>(); 82 | // 头5 4 3 2 1 100 101 102 103 104 105 106 8 7 6 尾 83 | 84 | // 头 8 7 6 5 4 3 2 1 100 101 102 103 104 105 106 107 108 109 null null 10 9 尾 85 | for (int i = 0; i < 10; i++) { 86 | queue.enQueueFront(i + 1); 87 | queue.enQueueRear(i + 100); 88 | } 89 | 90 | // 头 null 7 6 5 4 3 2 1 100 101 102 103 104 105 106 null null null null null 91 | // null null 尾 92 | for (int i = 0; i < 3; i++) { 93 | queue.deQueueFront(); 94 | queue.deQueueRear(); 95 | } 96 | 97 | // 头 11 7 6 5 4 3 2 1 100 101 102 103 104 105 106 null null null null null null 98 | // 12 尾 99 | queue.enQueueFront(11); 100 | queue.enQueueFront(12); 101 | System.out.println("\n************************testCircleDeque************************\n"); 102 | 103 | System.out.println(queue); 104 | while (!queue.isEmpty()) { 105 | System.out.println(queue.deQueueFront()); 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /08-动态规划/src/com/dp/LCSubstring.java: -------------------------------------------------------------------------------- 1 | public class LCSubstring { 2 | public static void main(String[] args) { 3 | System.out.println(lcstring_dp2("ABCBA", "BABC")); 4 | } 5 | 6 | static int lcstring_dp0(String str1, String str2) { 7 | if (str1 == null || str2 == null) 8 | return 0; 9 | if (str1.length() == 0 || str2.length() == 0) 10 | return 0; 11 | char[] char1 = str1.toCharArray(); 12 | char[] char2 = str2.toCharArray(); 13 | 14 | // 代表以i和j结尾的公共子串 15 | int[][] dp = new int[char1.length + 1][char2.length + 1]; 16 | int max = 0; 17 | for (int i = 1; i <= char1.length; i++) { 18 | for (int j = 1; j <= char2.length; j++) { 19 | if (char1[i - 1] != char2[j - 1]) 20 | continue; 21 | dp[i][j] = dp[i - 1][j - 1] + 1; 22 | max = Math.max(dp[i][j], max); 23 | } 24 | } 25 | return max; 26 | } 27 | 28 | // 是用一维数组 优化方案 29 | //时间复杂度 O(n*m);空间复杂度O(K),k= min(m,n) 30 | static int lcstring_dp1(String str1, String str2) { 31 | if (str1 == null || str2 == null) 32 | return 0; 33 | if (str1.length() == 0 || str2.length() == 0) 34 | return 0; 35 | char[] char1 = str1.toCharArray(); 36 | char[] char2 = str2.toCharArray(); 37 | char[] rowChars = char1, colsChars = char2; 38 | if (char1.length < char2.length) { 39 | colsChars = char1; 40 | rowChars = char2; 41 | } 42 | 43 | // 代表以i和j结尾的公共子串 44 | int[] dp = new int[colsChars.length + 1]; 45 | int max = 0; 46 | for (int row = 1; row <= rowChars.length; row++) { 47 | int cur = 0; 48 | for (int col = 1; col <= colsChars.length; col++) { 49 | int leftTop = cur; 50 | cur = dp[col]; 51 | if (char1[row - 1] != char2[col - 1]) { 52 | dp[col] = 0; //数组默认虽然为零,但是因为是重复使用的原因,需要对之前可能的值进行覆盖,进行重置 53 | } else { 54 | dp[col] = leftTop + 1; 55 | } 56 | 57 | max = Math.max(dp[col], max); 58 | } 59 | } 60 | return max; 61 | } 62 | 63 | //掌握了0-1 背包问题后,可以使用同样的for循环递减的方式对该题进行优化 64 | static int lcstring_dp2(String str1, String str2) { 65 | if (str1 == null || str2 == null) 66 | return 0; 67 | if (str1.length() == 0 || str2.length() == 0) 68 | return 0; 69 | char[] char1 = str1.toCharArray(); 70 | char[] char2 = str2.toCharArray(); 71 | char[] rowChars = char1, colsChars = char2; 72 | if (char1.length < char2.length) { 73 | colsChars = char1; 74 | rowChars = char2; 75 | } 76 | 77 | // 代表以i和j结尾的公共子串 78 | int[] dp = new int[colsChars.length + 1]; 79 | int max = 0; 80 | for (int row = 1; row <= rowChars.length; row++) { 81 | int cur = 0; 82 | for (int col = colsChars.length; col >= 1; col--) { 83 | if (char1[row - 1] != char2[col - 1]) { 84 | dp[col] = 0; //数组默认虽然为零,但是因为是重复使用的原因,需要对之前可能的值进行覆盖,进行重置 85 | } else { 86 | dp[col] = dp[col-1] + 1; 87 | } 88 | max = Math.max(dp[col], max); 89 | } 90 | } 91 | return max; 92 | } 93 | 94 | } --------------------------------------------------------------------------------