├── .gitignore ├── .idea └── .gitignore ├── LICENSE ├── LeetCode 641. 设计循环双端队列.md ├── LeetCode . 142. 环形链表 II .md ├── LeetCode . 82. 删除排序链表中的重复元素 II.md ├── LeetCode 102. 二叉树的层次遍历.md ├── LeetCode 17. 电话号码的字母组合.md ├── LeetCode 2. 两数相加.md ├── LeetCode 20. 有效的括号.md ├── LeetCode 239. 滑动窗口最大值.md ├── LeetCode 559. N叉树的最大深度.md ├── LeetCode 739. 每日温度.md ├── LeetCode 8. 字符串转换整数 (atoi).md ├── LeetCode 804. 唯一摩尔斯密码词.md ├── LeetCode 832.翻转图像.md ├── LeetCode 905. 按奇偶排序数组.md ├── LeetCode 921. 使括号有效的最少添加.md ├── LeetCode 933. 最近的请求次数.md ├── LeetCode-500-键盘行.md ├── LeetCode-面试题 17.16. 按摩师.md ├── LeetCode. 15 - 三数之和.md ├── LeetCode. 23 - 合并 K个排序序列.md ├── LeetCode. 41 - 缺失的第一个正数.md ├── LeetCode. 950 按递增顺序显示卡牌.md ├── LeetCode.135分发糖果.md ├── LeetCode.141 - 环形链表.md ├── LeetCode.169 - 求众数.md ├── LeetCode.209单词规律.md ├── LeetCode.217存在重复元素.md ├── LeetCode.34. 在排序数组中查找元素的第一个和最后一个位置.md ├── LeetCode.370.区间加法器.md ├── LeetCode.387字符串中的第一个唯一字符.md ├── LeetCode.451-根据字符出现频率排序.md ├── LeetCode.617.合并二叉树.md ├── LeetCode.622. 设计循环队列.md ├── LeetCode.738单调递增的数字.md ├── LeetCode.783. 二叉搜索树结点最小距离.md ├── LeetCode.860柠檬水找零.md ├── LeetCode.861翻转矩阵后的得分.md ├── LeetCode.942 增减字符串匹配.md ├── LeetCode.973. 最接近原点的 K 个点.md ├── LeetCode.jpg ├── LeetCode10. 正则表达式匹配.md ├── LeetCode1013.md ├── LeetCode1018. 可被 5 整除的二进制前缀.md ├── LeetCode103.二叉树的锯齿形层序遍历.md ├── LeetCode104. 二叉树的最大深度.md ├── LeetCode1046. 最后一块石头的重量.md ├── LeetCode1047. 删除字符串中的所有相邻重复项.md ├── LeetCode1052. 爱生气的书店老板.md ├── LeetCode11. 盛最多水的容器.md ├── LeetCode111. 二叉树的最小深度.md ├── LeetCode1128.等价多米诺骨牌对的数量.md ├── LeetCode1160. 拼写单词.md ├── LeetCode1162. 地图分析.md ├── LeetCode118. 杨辉三角.md ├── LeetCode12. 整数转罗马数字.md ├── LeetCode120. 三角形最小路径和.md ├── LeetCode1208. 尽可能使字符串相等.md ├── LeetCode121. 买卖股票的最佳时机.md ├── LeetCode122. 买卖股票的最佳时机 II.md ├── LeetCode123. 买卖股票的最佳时机 III.md ├── LeetCode1232.缀点成线.md ├── LeetCode124. 二叉树中的最大路径和.md ├── LeetCode13. 罗马数字转整数.md ├── LeetCode14. 最长公共前缀.md ├── LeetCode1423. 可获得的最大点数.md ├── LeetCode151. 翻转字符串里的单词.md ├── LeetCode153. 寻找旋转排序数组中的最小值.md ├── LeetCode16. 最接近的三数之和.md ├── LeetCode164. 最大间距.md ├── LeetCode18. 四数之和.md ├── LeetCode188. 买卖股票的最佳时机 IV.md ├── LeetCode189. 旋转数组.md ├── LeetCode19. 删除链表的倒数第N个节点.md ├── LeetCode191. 位1的个数.md ├── LeetCode200. 岛屿数量.md ├── LeetCode202.快乐数.md ├── LeetCode204. 计数质数.md ├── LeetCode205. 同构字符串.md ├── LeetCode208. 实现 Trie (前缀树).md ├── LeetCode21. 合并两个有序链表.md ├── LeetCode212. 单词搜索 II.md ├── LeetCode22. 括号生成.md ├── LeetCode228. 汇总区间.md ├── LeetCode229. 求众数 II.md ├── LeetCode231. 2的幂.md ├── LeetCode235. 二叉搜索树的最近公共祖先.md ├── LeetCode24. 两两交换链表中的节点.md ├── LeetCode25. K 个一组翻转链表.md ├── LeetCode26.删除排序数组中的重复项.md ├── LeetCode27. 移除元素.md ├── LeetCode28. 实现strStr().md ├── LeetCode289. 生命游戏.md ├── LeetCode29. 两数相除.md ├── LeetCode3. 无重复字符的最长子串.md ├── LeetCode30. 串联所有单词的子串.md ├── LeetCode300. 最长上升子序列.md ├── LeetCode31. 下一个排列.md ├── LeetCode316去除重复字母.md ├── LeetCode32. 最长有效括号.md ├── LeetCode322. 零钱兑换.md ├── LeetCode33. 搜索旋转排序数组.md ├── LeetCode330. 按要求补齐数组.md ├── LeetCode334. 递增的三元子序列.md ├── LeetCode338. 比特位计数.md ├── LeetCode345. 反转字符串中的元音字母.md ├── LeetCode347. 前 K 个高频元素.md ├── LeetCode35. 搜索插入位置.md ├── LeetCode36. 有效的数独.md ├── LeetCode365. 水壶问题.md ├── LeetCode37. 解数独.md ├── LeetCode38. 报数.md ├── LeetCode39. 组合总和.md ├── LeetCode395. 至少有 K 个重复字符的最长子串.md ├── LeetCode398. 找不同.md ├── LeetCode4. 寻找两个有序数组的中位数.md ├── LeetCode40. 组合总和 II.md ├── LeetCode409. 最长回文串.md ├── LeetCode42. 接雨水.md ├── LeetCode435. 无重叠区间.md ├── LeetCode445. 两数相加 II.md ├── LeetCode45. 跳跃游戏 II.md ├── LeetCode452. 用最少数量的箭引爆气球.md ├── LeetCode455. 分发饼干.md ├── LeetCode46. 全排列.md ├── LeetCode460. LFU缓存.md ├── LeetCode48. 旋转图像.md ├── LeetCode49. 字母异位词分组.md ├── LeetCode5. 最长回文子串.md ├── LeetCode50. Pow(x, n).md ├── LeetCode509. 斐波那契数.md ├── LeetCode51. N皇后.md ├── LeetCode52. N皇后 II.md ├── LeetCode524. 通过删除字母匹配到字典里最长单词.md ├── LeetCode53. 最大子序和.md ├── LeetCode54. 螺旋矩阵.md ├── LeetCode542. 01 矩阵.md ├── LeetCode547. 省份数量.md ├── LeetCode55. 跳跃游戏.md ├── LeetCode56. 合并区间.md ├── LeetCode567. 字符串的排列.md ├── LeetCode57. 插入区间.md ├── LeetCode58. 最后一个单词的长度.md ├── LeetCode6. Z 字形变换.md ├── LeetCode605. 种花问题.md ├── LeetCode61. 旋转链表.md ├── LeetCode62. 不同路径.md ├── LeetCode621. 任务调度器.md ├── LeetCode628. 三个数的最大乘积.md ├── LeetCode63. 不同路径 II.md ├── LeetCode633. 平方数之和.md ├── LeetCode64. 最小路径和.md ├── LeetCode643. 子数组最大平均数 I.md ├── LeetCode674. 最长连续递增序列.md ├── LeetCode69. x 的平方根.md ├── LeetCode695. 岛屿的最大面积.md ├── LeetCode697. 数组的度.md ├── LeetCode7. 整数反转.md ├── LeetCode70. 爬楼梯.md ├── LeetCode703. 数据流中的第K大元素.md ├── LeetCode714. 买卖股票的最佳时机含手续费.md ├── LeetCode72. 编辑距离.md ├── LeetCode724. 寻找数组的中心索引.md ├── LeetCode73. 矩阵置零.md ├── LeetCode746.使用最小花费爬楼梯.md ├── LeetCode75. 颜色分类.md ├── LeetCode763. 划分字母区间.md ├── LeetCode778.水位上升的泳池中游泳.md ├── LeetCode78. 子集.md ├── LeetCode79. 单词搜索.md ├── LeetCode8. 字符串转换整数 (atoi).md ├── LeetCode82. 删除排序链表中的重复元素 II.md ├── LeetCode820. 单词的压缩编码.md ├── LeetCode830. 较大分组的位置.md ├── LeetCode836. 矩形重叠.md ├── LeetCode84. 柱状图中最大的矩形.md ├── LeetCode842.md ├── LeetCode85. 最大矩形.md ├── LeetCode86. 分隔链表.md ├── LeetCode867. 转置矩阵.md ├── LeetCode876. 链表的中间结点.md ├── LeetCode888. 公平的糖果棒交换.md ├── LeetCode892. 三维形体的表面积.md ├── LeetCode896. 单调数列.md ├── LeetCode9.回文数.md ├── LeetCode912. 排序数组.md ├── LeetCode914. 卡牌分组.md ├── LeetCode945. 使数组唯一的最小增量.md ├── LeetCode989. 数组形式的整数加法.md ├── LeetCode999. 车的可用捕获量.md ├── LeetCode· 88. 合并两个有序数组.md ├── LeetCode面试题 01.07. 旋转矩阵.md ├── LeetCode面试题13. 机器人的运动范围.md ├── LeetCode面试题62. 圆圈中最后剩下的数字.md ├── Leetcode 215. 数组中的第K个最大元素.md ├── README.md ├── [1094]拼车.java ├── [1109]航班预订统计.java ├── [26]删除有序数组中的重复项.java ├── [27]移除元素.java ├── [283]移动零.java ├── [5]最长回文子串.java ├── [83]删除排序链表中的重复元素.java ├── img ├── jetbrains.png └── 数据结构与算法.png ├── leetcode └── editor │ └── cn │ ├── [1011]在 D 天内送达包裹的能力.java │ ├── [102]二叉树的层序遍历.java │ ├── [111]二叉树的最小深度.java │ ├── [114]二叉树展开为链表.java │ ├── [116]填充每个节点的下一个右侧节点指针.java │ ├── [141]环形链表.java │ ├── [142]环形链表 II.java │ ├── [146]LRU 缓存.java │ ├── [160]相交链表.java │ ├── [19]删除链表的倒数第 N 个结点.java │ ├── [225]用队列实现栈.java │ ├── [226]翻转二叉树.java │ ├── [22]括号生成.java │ ├── [232]用栈实现队列.java │ ├── [239]滑动窗口最大值.java │ ├── [300]最长递增子序列.java │ ├── [322]零钱兑换.java │ ├── [34]在排序数组中查找元素的第一个和最后一个位置.java │ ├── [3]无重复字符的最长子串.java │ ├── [438]找到字符串中所有字母异位词.java │ ├── [450]删除二叉搜索树中的节点.java │ ├── [460]LFU 缓存.java │ ├── [46]全排列.java │ ├── [496]下一个更大元素 I.java │ ├── [503]下一个更大元素 II.java │ ├── [509]斐波那契数.java │ ├── [51]N 皇后.java │ ├── [53]最大子数组和.java │ ├── [567]字符串的排列.java │ ├── [700]二叉搜索树中的搜索.java │ ├── [701]二叉搜索树中的插入操作.java │ ├── [704]二分查找.java │ ├── [70]爬楼梯.java │ ├── [739]每日温度.java │ ├── [752]打开转盘锁.java │ ├── [76]最小覆盖子串.java │ ├── [875]爱吃香蕉的珂珂.java │ ├── [876]链表的中间结点.java │ ├── [98]验证二叉搜索树.java │ └── [990]等式方程的可满足性.java └── out └── production └── LeetCode ├── .gitignore └── .idea └── .gitignore /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea/LeetCode.iml 3 | .idea/leetcode/editor.xml 4 | .idea/misc.xml 5 | .idea/modules.xml 6 | .idea/vcs.xml 7 | /out/ 8 | /leetcode/editor/cn/doc/content/ 9 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /LeetCode . 142. 环形链表 II .md: -------------------------------------------------------------------------------- 1 | # 142. 环形链表 II [题目链接](https://leetcode-cn.com/problems/linked-list-cycle-ii/) 2 | 3 | > 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 4 | >为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 5 | 6 | >说明:不允许修改给定的链表。 7 | 8 | >示例 1: 9 | >输入:head = [3,2,0,-4], pos = 1 10 | >输出:tail connects to node index 1 11 | >解释:链表中有一个环,其尾部连接到第二个节点。 12 | 13 | ***解题思路:*** 14 | 15 | 画图找规律 16 | 17 | 出现环路的首节点为 A ,而快慢指针第一次相遇的点为 A + B 即环长 18 | 19 | B 为环内重复段长度 20 | 21 | 再让一点从首结点出发,与慢指针相交结点必为 A 点 22 | ```c 23 | 24 | struct ListNode* hasCycle(struct ListNode *head) { // 判断是否有环路,若有则返回慢指针,无则返回 NULL 25 | struct ListNode *q = head; 26 | delete(q); 27 | struct ListNode *fast, *slow; 28 | slow = fast = head; 29 | while (fast&&fast->next&&fast->next->next) 30 | { 31 | fast = fast->next->next; 32 | slow = slow->next; 33 | if (slow == fast) 34 | return slow; 35 | } 36 | return NULL; 37 | } 38 | 39 | struct ListNode *detectCycle(struct ListNode *head) { 40 | struct ListNode* result = hasCycle(head), 41 | *p = head; 42 | 43 | if (!result) 44 | return NULL; 45 | else 46 | { 47 | while (p != result) 48 | { 49 | p = p->next; 50 | result = result->next; 51 | } 52 | } 53 | return p; 54 | } 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /LeetCode . 82. 删除排序链表中的重复元素 II.md: -------------------------------------------------------------------------------- 1 | # 删除排序链表中的重复元素 II 2 | 3 | > 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。 4 | 5 | >示例 1: 6 | >输入: 1->2->3->3->4->4->5 7 | >输出: 1->2->5 8 | 9 | ***解题思路:*** 10 | 11 | 先借 1 个空结点指向头节点,方便头结点去重 12 | 13 | 去重,让指针向下遍历,若指针遍历出现与下 1 结点数据相同情况则让指针指向下一节点 14 | 15 | 若指针位置无变化,则说明无重复,则遍历下一结点 16 | 17 | 若指针位置变化说明已出现重复,则删除重复结点 18 | ```c 19 | struct ListNode* deleteDuplicates(struct ListNode* head) { 20 | struct ListNode *p = (struct ListNode*)malloc(sizeof(struct ListNode)), 21 | *node1, *node2; 22 | p->next = head; 23 | head = p; 24 | while (p->next) 25 | { 26 | node1 = p->next; 27 | node2 = node1; //记录 node1 之前的位置 28 | while (node1->next&&node1->next->val == node1->val)// 若不为空且与下一结点数值重复则指向下一结点 29 | node1 = node1->next; 30 | if (node1 == node2)//判断 node1 的位置是否变化 31 | p = p->next; 32 | else 33 | p->next = node1->next; 34 | } 35 | return head->next; 36 | } 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /LeetCode 102. 二叉树的层次遍历.md: -------------------------------------------------------------------------------- 1 | # 二叉树的层次遍历 [题目链接](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/) 2 | >给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点) 3 | 4 | 思路:按照 BFS(Breath-First-Search)广度优先搜素的方法,通过维护一个队列,依序将每次加入队列,再依序加入 list 即可 5 | ```java 6 | public List> levelOrder(TreeNode root) { 7 | List> list = new ArrayList<>(); // 定义一个为整型 List 的 List 集合,类似于交错数组 8 | if(root==null) return list; // 若 root 为空则无需遍历直接返还空集合 9 | int count =0 ; // 初始化 count ,记录每一层的节点数 10 | TreeNode node; // node 为遍历的任意结点 11 | Queue queue = new LinkedList(); // 维护 1 个队列将每一层的结点依序放入队列 12 | queue.add(root); // 先把第一层结点加入队列 13 | while(!queue.isEmpty()) // 队列不为空说明树还没有遍历结束 14 | { 15 | List res = new ArrayList<>(); // 存储每一层结点 16 | count=queue.size(); // 记录当前层的结点数 17 | while(count>0) 18 | { 19 | node=queue.poll(); 20 | if(node.left!=null) queue.add(node.left); // 将子层结点加入队列 21 | if(node.right!=null) queue.add(node.right); 22 | res.add(node.val); 23 | count--; 24 | } 25 | list.add(res); 26 | } 27 | return list; 28 | } 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /LeetCode 17. 电话号码的字母组合.md: -------------------------------------------------------------------------------- 1 | # 电话号码的字母组合 [题目链接](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/submissions/) 2 | >给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 3 | 4 | >给出数字到字母的映射与电话按键相同。注意 1 不对应任何字母。 5 | 6 | 思路分析:这类求解所有可能的题目,采用 [回溯法](https://baike.baidu.com/item/%E5%9B%9E%E6%BA%AF%E6%B3%95/86074?fr=aladdin) 结合 BFS 广度优先的思想来解答。 7 | 8 | 穷举每一种组合: 9 | 10 | 1. 每次取出当前遍历数字所代表的的字符串 strs ,组合字符串 combin 组合每一种情况,继续遍历下一数字 next_digits。 11 | 2. 若 next_digits 长度为 0 ,则一种组合诞生,将其加入组合集中 12 | 13 | 。 14 | 15 | ```java 16 | class Solution { 17 | Map map = new HashMap(){{ // 哈希表——存储键盘按键所对应的字符串 18 | put('2', "abc"); 19 | put('2', "abc"); 20 | put('3', "def"); 21 | put('4', "ghi"); 22 | put('5', "jkl"); 23 | put('6', "mno"); 24 | put('7', "pqrs"); 25 | put('8', "tuv"); 26 | put('9', "wxyz"); 27 | }}; 28 | 29 | List combins= new ArrayList(); // 返回的组合集 30 | public List letterCombinations(String digits) { 31 | if(digits.length()!=0){ 32 | backTrack("", digits); 33 | } 34 | return combins; 35 | } 36 | 37 | private void backTrack(String combin,String next_digits){ // 回溯,穷举所有组合 38 | if(next_digits.length()==0){ 39 | combins.add(combin); // 当 next_digits 长度为 0 说明已遍历完最后一个按键数 40 | } 41 | else{ 42 | String strs = map.get(next_digits.charAt(0)); // 取出按键所能表示的字符串 43 | for(int i=0;i 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高的天数。如果之后都不会升高,请输入 0 来代替。 4 | 5 | >例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。 6 | 7 | >提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的都是 [30, 100] 范围内的整数。 8 | 9 | 思路: 10 | 11 | 返回的天数实际就是与数组后遇见的第一个更大数组的索引差。 12 | 13 | 特殊情况:遍历完数组没有找到气温更高的数,则保持默认值 0。 14 | ```java 15 | public int[] dailyTemperatures(int[] T) { 16 | int count,len=T.length ; 17 | //int[] nums = new int[len]; 18 | 19 | for(int i=0;iT[i]) 25 | { 26 | count=j-i; 27 | break; 28 | } 29 | 30 | } 31 | T[i]=count; 32 | } 33 | 34 | 35 | return T; 36 | } 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /LeetCode 804. 唯一摩尔斯密码词.md: -------------------------------------------------------------------------------- 1 | # 唯一摩尔斯密码词 [题目链接](https://leetcode-cn.com/problems/unique-morse-code-words/) 2 | >国际摩尔斯密码定义一种标准编码方式,将每个字母对应于一个由一系列点和短线组成的字符串, 比如: "a" 对应 ".-", "b" 对应 "-...", "c" 对应 "-.-.", 等等。 3 | 4 | >为了方便,所有26个英文字母对应摩尔斯密码表如下: 5 | >[".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."] 6 | 7 | >给定一个单词列表,每个单词可以写成每个字母对应摩尔斯密码的组合。例如,"cab" 可以写成 "-.-..--...",(即 "-.-." + "-..." + ".-"字符串的结合)。我们将这样一个连接过程称作单词翻译。 8 | 9 | >返回我们可以获得所有词不同单词翻译的数量。 10 | 11 | 思路: 12 | 13 | 因为字符都是小写,所以 -'a' 就是对应的索引,把所有生成的新字符串加入哈希表,利用哈希表的唯一性原则,去除重复,最后返回哈希表中的元素数量就能知道有多少不同翻译了。 14 | ```java 15 | class Solution { 16 | public int uniqueMorseRepresentations(String[] words) { 17 | String[] map ={".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."}; 18 | String temp; 19 | HashSet hashMap=new HashSet<>(); 20 | for (String word : words) { 21 | temp=""; 22 | for(int i=0;i给定一个非负整数数组 A,返回一个由 A 的所有偶数元素组成的数组,后面跟 A 的所有奇数元素。 4 | 5 | >你可以返回满足此条件的任何数组作为答案。 6 | >示例: 7 | >输入:[3,1,2,4] 8 | >输出:[2,4,3,1] 9 | >输出 [4,2,3,1],[2,4,1,3] 和 [4,2,1,3] 也会被接受。 10 | 11 | 解题思路:这里将判断是否为偶数改为了「&」(与运算),当计算数据量过大时「&」运算比求余运算的效率更高,更节省内存 12 | 同时将奇数和偶数分别用两个变量标记,偶数则按题要求从前往后放入数组,奇数则从后往前放入数组。用前缀表达式节省了一个变量 13 | ```c 14 | int* sortArrayByParity(int* A, int ASize, int* returnSize) { 15 | *returnSize = 0; 16 | int i = 0,k=ASize,*newA=(int *)malloc(ASize*sizeof(int)); 17 | for (; i < ASize; i++) 18 | if ((A[i] &1) == 0) 19 | newA[(*returnSize)++] = A[i]; 20 | else 21 | newA[--k] = A[i]; 22 | (*returnSize) = ASize; 23 | return newA; 24 | } 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /LeetCode 921. 使括号有效的最少添加.md: -------------------------------------------------------------------------------- 1 | # 使括号有效的最少添加 [题目链接](https://leetcode-cn.com/problems/minimum-add-to-make-parentheses-valid/) 2 | 3 | > 给定一个由 '(' 和 ')' 括号组成的字符串 S,我们需要添加最少的括号( '(' 或是 ')',可以在任何位置),以使得到的括号字符串有效。 4 | 5 | >从形式上讲,只有满足下面几点之一,括号字符串才是有效的: 6 | >它是一个空字符串,或者 7 | >它可以被写成 AB (A 与 B 连接), 其中 A 和 B 都是有效字符串,或者 8 | >它可以被写作 (A),其中 A 是有效字符串。 9 | >给定一个括号字符串,返回为使结果字符串有效而必须添加的最少括号数。 10 | 11 | 思路: 12 | 13 | 1、将传入字符串转换成数组。定义一个字符型栈,将字符压栈。 14 | 15 | 2、当栈不为空时比较栈顶字符与新遍历字符是否能够合并为完整括号,满足则出栈,否则入栈。 16 | 17 | 3、字符遍历结束,栈中元素个数即Wie必须添加的最少括号数。 18 | ```java 19 | class Solution { 20 | private boolean IsBH(char cr1,char cr2) 21 | { 22 | //当栈顶为前括号,cr 为后括号时返回 True 23 | return cr1=='('&&cr2==')'; 24 | } 25 | 26 | public int minAddToMakeValid(String S) { 27 | //int count =0; 28 | Stack stk1=new Stack<>(); 29 | char[] str=S.toCharArray(); 30 | 31 | for(char c :str) 32 | { 33 | if(stk1.size()==0) 34 | stk1.push(c); 35 | else if(IsBH(stk1.peek(), c)) 36 | { 37 | stk1.pop(); 38 | } 39 | else 40 | { 41 | stk1.push(c); 42 | } 43 | } 44 | 45 | 46 | return stk1.size(); 47 | } 48 | } 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /LeetCode 933. 最近的请求次数.md: -------------------------------------------------------------------------------- 1 | # 最近的请求次数 [题目链接](https://leetcode-cn.com/problems/number-of-recent-calls/) 2 | 3 | > 写一个 RecentCounter 类来计算最近的请求。 4 | >它只有一个方法:ping(int t),其中 t 代表以毫秒为单位的某个时间。 5 | >返回从 3000 毫秒前到现在的 ping 数。 6 | >任何处于 [t - 3000, t] 时间范围之内的 ping 都将会被计算在内,包括当前(指 t 时刻)的 ping。 7 | >保证每次对 ping 的调用都使用比之前更大的 t 值。 8 | 9 | >示例: 10 | >输入:inputs = ["RecentCounter","ping","ping","ping","ping"], inputs = [[],[1],[100],[3001],[3002]] 11 | >输出:[null,1,2,3,3] 12 | 13 | ```java 14 | class RecentCounter { 15 | private Queue que ; 16 | public RecentCounter() { 17 | que=new LinkedList(); 18 | } 19 | 20 | public int ping(int t) { 21 | que.offer(t); // 先入队 22 | if(!que.isEmpty()&&que.peek()<3000-t) // 因为 t 会一直增大,所以只要判断队首是否小于 3000-t 23 | { 24 | que.poll(); // 出队 25 | } 26 | return que.size(); // 队列中剩余元素个数即有效请求数 27 | } 28 | } 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /LeetCode-500-键盘行.md: -------------------------------------------------------------------------------- 1 | # 键盘行 [题目链接](https://leetcode-cn.com/problems/keyboard-row/) 2 | > 给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词 3 | 4 | 思路:根据传入字符串的首字母判断是在哪一行,若出现不同行的字符则结束查找,所有字符皆在同一行则放入返回的字符串数组中。 5 | ```java 6 | public String[] findWords(String[] words) { 7 | String[] str ={"QWERTYUIOP","ASDFGHJKL","ZXCVBNM"}; 8 | int count; 9 | int index; 10 | String test; 11 | List new_words = new LinkedList(); // 定义一个 String 类型链表,存储属于同一行的输入 12 | for (String word : words) { 13 | count=0; // 记录符合长度的元素个数 14 | test =String.valueOf(word.toUpperCase().charAt(0)) ; 15 | if(str[0].contains(test)) // 根据首字母判断是属于哪一行 16 | { 17 | index=0; 18 | } 19 | else if(str[1].contains(test)) 20 | { 21 | index=1; 22 | } 23 | else{ 24 | index=2; 25 | } 26 | for (char c : word.toUpperCase().toCharArray()) { 27 | if(str[index].contains(String.valueOf(c))) 28 | { 29 | count+=1; 30 | } 31 | else 32 | break; // 若出现不属于同一行的字母则结束循环 33 | } 34 | if(count==word.length()) // 根据统计的符合的元素个数判断是否都在一行 35 | new_words.add(word); 36 | } 37 | return new_words.toArray(new String[0]); // 将泛型列表转换为字符串数组 38 | } 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /LeetCode-面试题 17.16. 按摩师.md: -------------------------------------------------------------------------------- 1 | # 面试题 17.16. 按摩师 [题目链接](https://leetcode-cn.com/problems/the-masseuse-lcci/) 2 | 解题思路:动态规划,由果溯因 3 | 4 | dp[n][0]表示不接受当前数的最大预约时长 = Max(dp[n-1][0],dp[n-1][1]) 5 | 6 | dp[n][1] 表示接受当前数的最大预约时长 = dp[n-1][0]+nums[n] 7 | 8 | 当前最大预约时长= Max(dp[n][0],dp[n][1]) 9 | ```java 10 | class Solution { 11 | public int massage(int[] nums) { 12 | if (nums == null || nums.length < 1) { 13 | return 0; 14 | } 15 | int dp0 = 0, dp1 = nums[0]; 16 | for (int i = 1; i < nums.length; i++) { 17 | int tempDp0 = dp0, tempDp1 = dp1; 18 | dp0 = Math.max(tempDp0, tempDp1); 19 | dp1 = tempDp0 + nums[i]; 20 | } 21 | return dp0 > dp1 ? dp0 : dp1; 22 | } 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /LeetCode. 23 - 合并 K个排序序列.md: -------------------------------------------------------------------------------- 1 | # 合并 K 个排序序列 [题目链接](https://leetcode-cn.com/problems/merge-k-sorted-lists/) 2 | 3 | > 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。 4 | >示例: 5 | >输入: 6 | >[ 7 | >1->4->5, 8 | >1->3->4, 9 | >2->6 10 | >] 11 | >输出: 1->1->2->3->4->4->5->6 12 | 13 | 解题思路:采用分治的思想,将 K 个链表的合并问题转换成,合并 2 个有序链表的问题 14 | ```c 15 | typedef struct ListNode List; // 定义一个 struct ListNode 类型 名为 List 16 | List *mergeTwoLists(List *list1, List *list2) 17 | { 18 | if (!list1&&!list2) return NULL;//当两条链表都为遍历结束则返回 NULL 19 | else if (!list1) return list2;//因为都是有序则一条遍历结束后只要将另一条链表接在后面即可 20 | else if (!list2) return list1; 21 | else if (list1->valval) 22 | { 23 | list1->next = mergeTwoLists(list1->next, list2); 24 | return list1; 25 | } 26 | else 27 | { 28 | list2->next = mergeTwoLists(list1, list2->next); 29 | return list2; 30 | } 31 | } 32 | struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) 33 | { 34 | if (listsSize == 0) return NULL; 35 | else if (listsSize == 1) return lists[0]; 36 | else if (listsSize == 2) return mergeTwoLists(lists[0], lists[1]); 37 | return mergeTwoLists(mergeKLists(lists, listsSize / 2), 38 | mergeKLists(lists + listsSize / 2, listsSize - listsSize / 2));//将 K 个链表分解成 2 个链表的组合 39 | } 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /LeetCode. 41 - 缺失的第一个正数.md: -------------------------------------------------------------------------------- 1 | # 缺失的第一个正数 [题目链接](https://leetcode-cn.com/problems/first-missing-positive/) 2 | 3 | > 给定一个未排序的整数数组,找出其中没有出现的最小的正整数。 4 | 5 | >示例 1: 6 | >输入: [1,2,0] 7 | >输出: 3 8 | 9 | >示例 2: 10 | >输入: [3,4,-1,1] 11 | >输出: 2 12 | 13 | >示例 3: 14 | >输入: [7,8,9,11,12] 15 | >输出: 1 16 | 17 | 参考了社区的解答。 18 | 19 | ***解题思路*** : 20 | 21 | 1、由题可得数组索引 index 对应的值为 index + 1,整个数组的取值范围为 [ 1 , length] (length 为数组长度即元素个数),且无重复。(可看做简单的 hashtable) 22 | 23 | 2、代码中的循环,在当前满足 nums[i] = i + 1 时 i++, 超出取值范围时将数值与末尾数交换,若是满足取值则进行对应索引值交换,直到满足 nums[i] = i + 1 24 | 25 | 最后输出的 length 为按升序排列的最大符合要求值,length + 1 则为缺失正数 26 | ```c 27 | void swap(int* nums, int a, int b) 28 | { 29 | int temp = nums[a]; 30 | nums[a] = nums[b]; 31 | nums[b] = temp; 32 | } 33 | int firstMissingPositive(int* nums, int numsSize) { 34 | int length = numsSize, i = 0; 35 | while (ilength || nums[i] == nums[nums[i]-1]) 39 | swap(nums, i, --length);//将不符合的数放在末尾 40 | else 41 | swap(nums,i,nums[i]-1); 42 | } 43 | return length + 1; 44 | } 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /LeetCode. 950 按递增顺序显示卡牌.md: -------------------------------------------------------------------------------- 1 | # 按递增顺序显示卡牌 [题目链接](https://leetcode-cn.com/problems/reveal-cards-in-increasing-order/) 2 | 3 | > 牌组中的每张卡牌都对应有一个唯一的整数。你可以按你想要的顺序对这套卡片进行排序。最初,这些卡牌在牌组里是正面朝下的(即,未显示状态)。 4 | 5 | >现在,重复执行以下步骤,直到显示所有卡牌为止: 6 | 从牌组顶部抽一张牌,显示它,然后将其从牌组中移出。 7 | 如果牌组中仍有牌,则将下一张处于牌组顶部的牌放在牌组的底部。 8 | 如果仍有未显示的牌,那么返回步骤 1。否则,停止行动。 9 | 返回能以递增顺序显示卡牌的牌组顺序。 10 | 答案中的第一张牌被认为处于牌堆顶部。 11 | 12 | >示例: 13 | 输入:[17,13,11,2,3,5,7] 14 | 输出:[2,13,3,11,5,17,7] 15 | 解释: 16 | 我们得到的牌组顺序为 [17,13,11,2,3,5,7](这个顺序不重要),然后将其重新排序。 17 | 重新排序后,牌组以 [2,13,3,11,5,17,7] 开始,其中 2 位于牌组的顶部。 18 | 我们显示 2,然后将 13 移到底部。牌组现在是 [3,11,5,17,7,13]。 19 | 我们显示 3,并将 11 移到底部。牌组现在是 [5,17,7,13,11]。 20 | 我们显示 5,然后将 17 移到底部。牌组现在是 [7,13,11,17]。 21 | 我们显示 7,并将 13 移到底部。牌组现在是 [11,17,13]。 22 | 我们显示 11,然后将 17 移到底部。牌组现在是 [13,17]。 23 | 我们展示 13,然后将 17 移到底部。牌组现在是 [17]。 24 | 我们显示 17。 25 | 由于所有卡片都是按递增顺序排列显示的,所以答案是正确的。 26 | 27 | ***解题思路***: 28 | 题目实际是循环队列问题(同报数问题类似),先对数组中的数排序,队列中首个空位放入最小数, 29 | 其后队列每隔 1 个空位放入 1 个数。 30 | 31 | ```c 32 | int cmp(const void *a, const void *b) 33 | { 34 | return *(int *)a - *(int *)b; 35 | } 36 | int* deckRevealedIncreasing(int* deck, int deckSize, int* returnSize) { 37 | *returnSize = deckSize; 38 | qsort(deck, deckSize, sizeof(deck[0]), cmp); 39 | int i = 0, 40 | n = 0, 41 | count = 1, 42 | *new_nums = (int *)malloc(deckSize*sizeof(deck)); 43 | for (; i < deckSize; i++) 44 | new_nums[i] = -1; 45 | i = 0; 46 | new_nums[0] = deck[0];// 第一张卡牌特殊处理 47 | while (count < deckSize) 48 | { 49 | //n %= deckSize; 50 | if (new_nums[n] == -1) 51 | { 52 | i++; 53 | if (i == 2)// 每隔 1 个有效位将卡牌依序放入 54 | { 55 | new_nums[n] = deck[count++];// 翻入新数组并计数 56 | i = 0; 57 | } 58 | } 59 | n++; 60 | if (n == deckSize)// 当 n 超出索引时置 0 61 | n = 0; 62 | } 63 | return new_nums; 64 | } 65 | ``` 66 | 67 | -------------------------------------------------------------------------------- /LeetCode.135分发糖果.md: -------------------------------------------------------------------------------- 1 | # LeetCode.135分发糖果 2 | 3 | #### [135. 分发糖果](https://leetcode-cn.com/problems/candy/) 4 | 5 | 解题思路: 6 | 7 | 1、左规则:若 ratings[n]> ratings[n-1] 则 left[n]必须大于 left[n-1] 8 | 9 | 2、右规则 若 ratings[n]> ratings[n+1] 则 right[n]必须大于 right[n+1] 10 | 11 | 3、最后发放糖果时必须同时满足左规则、右规则,所以取左右规则最大值 12 | 13 | ```java 14 | public int candy(int[] ratings) { 15 | if (ratings.length < 1) { 16 | return 0; 17 | } 18 | int len = ratings.length; 19 | int[] left = new int[len]; 20 | left[0] = 1; 21 | for (int i = 1; i < len; i++) { 22 | if (ratings[i] > ratings[i - 1]) { 23 | left[i] = left[i - 1] + 1; 24 | } else { 25 | left[i] = 1; 26 | } 27 | } 28 | int right = 1, result = left[len - 1]; 29 | for (int i = len - 2; i >= 0; i--) { 30 | if (ratings[i] > ratings[i + 1]) { 31 | right++; 32 | } else { 33 | right = 1; 34 | } 35 | result += Math.max(right, left[i]); 36 | } 37 | return result; 38 | } 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /LeetCode.141 - 环形链表.md: -------------------------------------------------------------------------------- 1 | # 环形链表 [题目链接](https://leetcode-cn.com/problems/linked-list-cycle/) 2 | 3 | > 给定一个链表,判断链表中是否有环。 4 | >为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 5 | 6 | >示例 1: 7 | >输入:head = [3,2,0,-4], pos = 1 8 | >输出:true 9 | >解释:链表中有一个环,其尾部连接到第二个节点。 10 | 11 | >示例 2: 12 | >输入:head = [1,2], pos = 0 13 | >输出:true 14 | >解释:链表中有一个环,其尾部连接到第一个节点。 15 | 16 | >示例 3: 17 | >输入:head = [1], pos = -1 18 | >输出:false 19 | >解释:链表中没有环。 20 | 21 | ***解题思路***:链表中常用快慢指针的方法来解决类似题目,快指针为慢指针的两倍速,若快指针经过 NULL 则无环路,若快指针和满指针指向同一结点则链表有环形。 22 | ```c 23 | /** 24 | * Definition for singly-linked list. 25 | * struct ListNode { 26 | * int val; 27 | * struct ListNode *next; 28 | * }; 29 | */ 30 | bool hasCycle(struct ListNode *head) { 31 | if (!head||!(head->next))return false; 32 | struct ListNode* slow = head, *fast = head->next->next; 33 | while (fast&&fast->next) 34 | { 35 | if (slow == fast) 36 | return true; 37 | else 38 | { 39 | slow = slow->next; 40 | fast = fast->next->next; 41 | } 42 | } 43 | return false; 44 | } 45 | ``` 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /LeetCode.169 - 求众数.md: -------------------------------------------------------------------------------- 1 | # 求众数 [题目链接](https://leetcode-cn.com/problems/majority-element/) 2 | 3 | > 给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 4 | >你可以假设数组是非空的,并且给定的数组总是存在众数。 5 | 6 | >示例 1: 7 | >输入: [3,2,3] 8 | >输出: 3 9 | 10 | >示例 2: 11 | >输入: [2,2,1,1,1,2,2] 12 | >输出: 2 13 | 14 | ***解题思路***:将数组排序,统计每个数字出现的次数,当满足众数条件时返回。时间复杂度 nlogn 15 | ```c 16 | int compare(const void *a, const void *b) 17 | { 18 | return (*(int*)a - *(int*)b); 19 | } 20 | int majorityElement(int* nums, int numsSize) { 21 | qsort(nums,numsSize,sizeof(int), compare); 22 | int num = nums[0],flag=numsSize>>1,count=1; 23 | for (int i = 1; i < numsSize; i++) 24 | { 25 | if (nums[i] != num) 26 | { 27 | num = nums[i]; count = 1; 28 | } 29 | else 30 | { 31 | count++; 32 | } 33 | if (count > flag) 34 | break; 35 | } 36 | return num; 37 | } 38 | ``` 39 | 更优解 40 | 41 | 提示:数组元素为奇数个,众数数量大于半数,所以相互抵消后最后剩余的一定为众数 42 | ```c 43 | int majorityElement(int* nums, int numsSize) 44 | { 45 | int count = 1,num=nums[0]; 46 | for (int i = 1; i < numsSize; i++) 47 | if (count == 0 || num == nums[i]) 48 | { 49 | count++; num = nums[i]; 50 | } 51 | else 52 | count--; 53 | return num; 54 | } 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /LeetCode.209单词规律.md: -------------------------------------------------------------------------------- 1 | # LeetCode.209单词规律 2 | 3 | #### [290. 单词规律](https://leetcode-cn.com/problems/word-pattern/) 4 | 5 | 解题思路:双哈希表法 6 | 7 | 1、同时遍历 pattern 与 s 字符串,若 pattern 字符数量 s 字符串数 不相等,说明无法匹配,返回 false 8 | 2、建立两个哈希表,表明映射关系,strMap 以 s 字符为 key , pattern 字符为 value;patternMap 以 pattern 字符为 key , s 字符为 value 9 | 3、当同一key 对应不同 value 时,说明模式不匹配,返回 false 10 | 11 | ```java 12 | public boolean wordPattern(String pattern, String s) { 13 | String[] strs = s.split(" "); 14 | char[] chars = pattern.toCharArray(); 15 | // 长度不一致,说明无法匹配 16 | if (strs.length != chars.length) { 17 | return false; 18 | } 19 | String[] patternMap = new String[26]; 20 | Map strMap = new HashMap<>(26); 21 | // 构建双哈希表,判断互相映射关系是否成立 22 | for (int i = 0; i < strs.length; i++) { 23 | if (!strMap.containsKey(strs[i]) && patternMap[chars[i] - 'a'] == null) { 24 | strMap.put(strs[i], chars[i]); 25 | patternMap[chars[i] - 'a'] = strs[i]; 26 | continue; 27 | } 28 | if (strMap.get(strs[i])==null|| 29 | patternMap[chars[i] - 'a']==null || 30 | !strMap.get(strs[i]).equals(chars[i]) || 31 | !strs[i].equals(patternMap[chars[i] - 'a'])) { 32 | return false; 33 | } 34 | } 35 | return true; 36 | } 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /LeetCode.370.区间加法器.md: -------------------------------------------------------------------------------- 1 | # LeetCode.370.区间加法器 2 | 3 | 解法:差分数组 4 | 5 | ```java 6 | class Difference{ 7 | private int[] diff; 8 | 9 | public Difference(int[] nums) { 10 | assert nums.length > 0; 11 | diff = new int[nums.length]; 12 | // 构造差分数组 13 | diff[0] = nums[0]; 14 | for (int i = 1; i < nums.length; i++) { 15 | diff[i] = nums[i] - nums[i - 1]; 16 | } 17 | } 18 | 19 | public void increment(int i, int j, int value) { 20 | diff[i] += val; 21 | if (j + 1 < diff.length) { 22 | diff[j + 1] -= value; 23 | } 24 | } 25 | 26 | public int[] result() { 27 | int[] res = new int[diff.length]; 28 | res[0] = diff[0]; 29 | for (int i = 1; i < diff.length; i++) { 30 | res[i] = res[i - 1] + diff[i]; 31 | } 32 | return res; 33 | } 34 | } 35 | ``` -------------------------------------------------------------------------------- /LeetCode.617.合并二叉树.md: -------------------------------------------------------------------------------- 1 | # 合并二叉树 [题目链接](https://leetcode-cn.com/problems/merge-two-binary-trees/) 2 | >给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。 3 | >你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。 4 | 5 | 解法一 6 | 7 | 根据中序遍历的思路对两棵树同时遍历,当某一树遍历结束则返回。 8 | 9 | 以 t1 树作为最终要返回的值,判断首次返回时 t1 的子节点是否为空,是则让 t1 的子节点指针指向 t2 的子节点。 10 | ```java 11 | class Solution { 12 | public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { 13 | if(t1==null) // 对特殊情况进行处理 14 | return t2; 15 | inTwoTree(t1, t2); 16 | return t1; 17 | } 18 | 19 | private void inTwoTree(TreeNode t1,TreeNode t2) // 递归遍历两树,某树遍历到空则返回 20 | { 21 | if(t1==null||t2==null) 22 | return ; 23 | inTwoTree(t1.left, t2.left); 24 | if(t1.left==null) 25 | t1.left=t2.left; 26 | t1.val+=t2.val; 27 | inTwoTree(t1.right, t2.right); 28 | if(t1.right==null) 29 | t1.right=t2.right; 30 | } 31 | } 32 | ``` 33 | 解法二 34 | 35 | 来自于官方提供的 [递归法](https://leetcode.com/problems/merge-two-binary-trees/solution/) 36 | 采用的是二叉树前序遍历的思路,若两树有一棵遍历为空,则将剩余部分(非重叠部分)返回给 t1。 37 | ```java 38 | public class Solution { 39 | public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { 40 | // inTwoTree(t1, t2); 41 | // 前序遍历,若有 1 棵树遍历结束则返回另一棵树剩余部分 42 | if(t1==null) 43 | return t2; 44 | if(t2==null) 45 | return t1; 46 | t1.val+=t2.val; 47 | t1.right=mergeTrees(t1.right, t2.right); 48 | t1.right=mergeTrees(t1.right, t2.right); 49 | return t1; 50 | } 51 | } 52 | ``` 53 | 54 | -------------------------------------------------------------------------------- /LeetCode.783. 二叉搜索树结点最小距离.md: -------------------------------------------------------------------------------- 1 | # 二叉搜索树结点最小距离 [题目链接](https://leetcode-cn.com/problems/minimum-absolute-difference-in-bst/) 2 | >给定一个二叉搜索树的根结点 root, 返回树中任意两节点的差的最小值。 3 | 4 | 思路:通过二叉树中序遍历的思路对树进行遍历。这里的任意两节点指的是相邻结点的差值 5 | ```java 6 | /** 7 | * Definition for a binary tree node. 8 | * public class TreeNode { 9 | * int val; 10 | * TreeNode left; 11 | * TreeNode right; 12 | * TreeNode(int x) { val = x; } 13 | * } 14 | */ 15 | class Solution { 16 | private int min = Integer.MAX_VALUE; // 定义要返回的最小值 17 | private TreeNode pre; // 前驱指针 18 | 19 | public int getMinimumDifference(TreeNode root) { 20 | inPrint(root); // 中序遍历二叉树 21 | return min; 22 | } 23 | 24 | private void inPrint(TreeNode root) { 25 | if (root == null) 26 | return; 27 | inPrint(root.left); // 先向左遍历到最高层 28 | 29 | if (pre != null) 30 | min = Math.min(min, Math.abs(root.val - pre.val)); // 比较最小值和相邻节点的差值哪个更小 31 | pre = root; // 前驱指针指向子一节点 32 | inPrint(root.right); // 再遍历右节点 33 | } 34 | } 35 | ``` 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /LeetCode.942 增减字符串匹配.md: -------------------------------------------------------------------------------- 1 | # 增减字符串匹配 [题目链接](https://leetcode-cn.com/problems/di-string-match/) 2 | > 给定只含 "I"(增大)或 "D"(减小)的字符串 S ,令 N = S.length。 3 | >返回 [0, 1, ..., N] 的任意排列 A 使得对于所有 i = 0, ..., N-1,都有: 4 | >如果 S[i] == "I",那么 A[i] < A[i+1] 5 | >如果 S[i] == "D",那么 A[i] > A[i+1] 6 | 7 | >示例 1: 8 | >输出:"IDID" 9 | >输出:[0,4,1,3,2] 10 | 11 | >示例 2: 12 | >输出:"III" 13 | 输出:[0,1,2,3] 14 | 15 | >示例 3: 16 | >输出:"DDI" 17 | >输出:[3,2,0,1] 18 | 19 | 原始代码,注意 returnSize 是没有初始值的,要根据字符串长度进行复制(代码中使用的是 strlen() 方法) 20 | ```c 21 | /** 22 | * Return an array of size *returnSize. 23 | * Note: The returned array must be malloced, assume caller calls free(). 24 | */ 25 | int* diStringMatch(char* S, int* returnSize) { 26 | *returnSize = strlen(S)+1; 27 | int *nums = (int *)malloc((*returnSize)*sizeof(int)), i = 0, count = 0,n=*returnSize-1; 28 | for (; i <*returnSize-1; i++) 29 | { 30 | if (*S == 'I') 31 | { 32 | nums[i] = count++; 33 | nums[i + 1] = nums[i] + 1; 34 | } 35 | else 36 | { 37 | nums[i] = n--; 38 | nums[i + 1] = nums[i] - 1; 39 | } 40 | S++; 41 | } 42 | return nums; 43 | } 44 | ``` 45 | 根据社区的其他解答进行了代码简化 46 | 47 | ***解题思路***:因为返回的数组长度为字符串长度 +1,通过规律可以发现,结尾多出的数恒为 n(当前减小数) 48 | 每出现一个 D 则 n--,若未出现 D 则最后排列的增大数恒为 returnSize-1。 49 | ```c 50 | int* diStringMatch(char* S, int* returnSize) { 51 | *returnSize = strlen(S)+1; 52 | int *nums = (int *)malloc((*returnSize)*sizeof(int)), i = 0, count = 0,n=*returnSize-1; 53 | for (; i <*returnSize; i++) 54 | nums[i]=S[i]=='I'?count++:n--; 55 | return nums; 56 | } 57 | ``` 58 | 59 | -------------------------------------------------------------------------------- /LeetCode.973. 最接近原点的 K 个点.md: -------------------------------------------------------------------------------- 1 | # 最接近原点的 K 个点 2 | 3 | > 我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。 4 | >(这里,平面上两点之间的距离是欧几里德距离。) 5 | >你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。 6 | 7 | >示例 1: 8 | >输入:points = [[1,3],[-2,2]], K = 1 9 | >输出:[[-2,2]] 10 | 11 | >解释: 12 | (1, 3) 和原点之间的距离为 sqrt(10), 13 | (-2, 2) 和原点之间的距离为 sqrt(8), 14 | 由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。 15 | 我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]。 16 | 17 | >示例 2: 18 | >输入:points = [[3,3],[5,-1],[-2,4]], K = 2 19 | >输出:[[3,3],[-2,4]] 20 | >(答案 [[-2,4],[3,3]] 也会被接受。) 21 | 22 | ***解题思路***:用一个动态数组存储 poions 每个坐标的原点距离,再调用 库的 qsort() 对数组进行排序,找到距离按升序排序的第 K 个点距离,把所有小于这个距离的点放入要返回的数组中即可。 23 | ***可优化点***:记录排序前每个距离对应的坐标,可以在比较距离时少做一次重复的距离计算,减少内存消耗。 24 | ```c 25 | int count_sqrt(int x, int y) 26 | { 27 | return x*x + y*y; 28 | } 29 | int compare(const void *a, const void *b) 30 | { 31 | return (*(int*)a - *(int*)b); 32 | } 33 | int** kClosest(int** points, int pointsRowSize, int *pointsColSizes, int K, int** columnSizes, int* returnSize) { 34 | *returnSize = 0; 35 | int **arrys = (int **)malloc(K*sizeof(int *));// 要返回的二维数组 36 | int *points_sqrt = (int*)malloc(pointsRowSize*sizeof(int)); 37 | int* cols = (int*)malloc(K*sizeof(int)); 38 | for (int i = 0; i < pointsRowSize; i++) 39 | points_sqrt[i] = count_sqrt(points[i][0], points[i][1]); 40 | qsort(points_sqrt, pointsRowSize, sizeof(int), compare); 41 | for (int i = 0; i < pointsRowSize; i++) 42 | { 43 | if (count_sqrt(points[i][0], points[i][1]) <= points_sqrt[K - 1]) 44 | { 45 | cols[*returnSize] = 2; 46 | arrys[*returnSize] = (int*)malloc(2 * sizeof(int)); 47 | arrys[*returnSize][0] = points[i][0]; 48 | arrys[*returnSize][1] = points[i][1]; 49 | ++(*returnSize); 50 | } 51 | } 52 | *columnSizes = cols; 53 | free(points_sqrt); 54 | *returnSize = K; 55 | return arrys; 56 | } 57 | ``` 58 | 59 | -------------------------------------------------------------------------------- /LeetCode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackhu2019/LeetCode/672a41799423c4aba336ec73b5c265c2bb579bca/LeetCode.jpg -------------------------------------------------------------------------------- /LeetCode10. 正则表达式匹配.md: -------------------------------------------------------------------------------- 1 | # 正则表达式匹配 [题目里链接](https://leetcode-cn.com/problems/regular-expression-matching/) 2 | 3 | > 给定一个字符串 (s) 和一个字符模式 (p)。实现支持 '.' 和 '*' 的正则表达式匹配。 4 | 5 | > '.' 匹配任意单个字符。 6 | > '*' 匹配零个或多个前面的元素。 匹配应该覆盖整个字符串 (s) ,而不是部分字符串。 7 | 8 | > 说明: 9 | > s 可能为空,且只包含从 a-z 的小写字母。 10 | > p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。 11 | 12 | 参考:[中文社区解答](https://leetcode-cn.com/problems/regular-expression-matching/solution/dong-tai-gui-hua-dfs-by-wein/) 13 | 14 | 思路分析: 15 | 1. 当模式串为空时,字符串为空,则匹配成功,否则匹配失败。 16 | 2. 当模式串只有 1 个字符时,只有字符串也为 1 个且与模式串字符相等或模式串剩余字符为「.」能匹配成功。 17 | 3. 当模式串不止 1 个字符时,判断下一个模式串字符是否为 「 * 」 ,否则比较当前字符串与模式串字符是否相等或模式串字符为「.」是,将模式串与字符串去除当前遍历字符,递归匹配,否,匹配失败。 18 | 4. 若第二个模式串字符为 '*' 则判断当前二者字符是否匹配若后序字段满足匹配,匹配成功 19 | 5. 不满足则消除字符串与模式串当前字符相等字符,继续匹配后序字符串 20 | 21 | ```java 22 | class Solution { 23 | public boolean isMatch(String s, String p) { 24 | 25 | if(p.isEmpty()){ // 当模式串为空时,字符串为空,则匹配成功,否则匹配失败 26 | return s.isEmpty(); 27 | } 28 | else if(p.length()==1){ 29 | return s.length()==1&&(s.charAt(0)==p.charAt(0)||p.charAt(0)=='.'); 30 | } 31 | else if(p.charAt(1)!='*'){ // 判断模式串第二位不为 * 的情况 32 | return !s.isEmpty()&&(s.charAt(0)==p.charAt(0)||p.charAt(0)=='.')&&isMatch(s.substring(1), p.substring(1)); 33 | } 34 | else // 判断当模式串第二位为 * 的情况 35 | { 36 | while(!s.isEmpty()&&(s.charAt(0)==p.charAt(0)||p.charAt(0)=='.')){ 37 | if( isMatch(s, p.substring(2) ) ){ // 若后序字符串匹配成功则返回 true 38 | return true; 39 | } 40 | s=s.substring(1); // 消除字符串与模式串当前字符相等字符 41 | } 42 | return isMatch(s, p.substring(2)); // 继续匹配后序字符串 43 | } 44 | } 45 | } 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /LeetCode1018. 可被 5 整除的二进制前缀.md: -------------------------------------------------------------------------------- 1 | # LeetCode1018. 可被 5 整除的二进制前缀 2 | 3 | #### [1018. 可被 5 整除的二进制前缀](https://leetcode-cn.com/problems/binary-prefix-divisible-by-5/) 4 | 5 | 解题思路: 6 | 7 | 1、cur 记录上一位计算数值余数,每次遍历新一位数,更新 curr=(上一位余数*2+当前位数值)%5 8 | 2、resultList 记录结果集,若 curr%5==0,加入 true,否 加入 false 9 | 10 | ```java 11 | public List prefixesDivBy5(int[] A) { 12 | int curr = 0; 13 | List resultList = new ArrayList<>(A.length); 14 | for (int i = 0; i < A.length; i++) { 15 | curr = ((curr << 1) + A[i])%5; 16 | resultList.add(curr == 0); 17 | } 18 | return resultList; 19 | } 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /LeetCode103.二叉树的锯齿形层序遍历.md: -------------------------------------------------------------------------------- 1 | # LeetCode103.二叉树的锯齿形层序遍历 2 | 3 | #### [103. 二叉树的锯齿形层序遍历](https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/) 4 | 5 | 解题思路:广度优先遍历 6 | 7 | 每次遍历当层节点,若是奇数层则从左往右加入List,若是偶数层则从右往左加入 List ( 双端队列实现 ) 8 | 9 | ```java 10 | public List> zigzagLevelOrder(TreeNode root) { 11 | List> resultList = new ArrayList<>(); 12 | if (root == null) { 13 | return resultList; 14 | } 15 | Queue queue = new LinkedList<>(); 16 | queue.add(root); 17 | // 区分当前是否奇数层,选择加入 List 顺序 18 | boolean isOddFloor = true; 19 | // 广度优先遍历 20 | while (!queue.isEmpty()) { 21 | int size = queue.size(); 22 | Deque nums = new LinkedList<>(); 23 | for (int i = 0; i < size; i++) { 24 | TreeNode curNode = queue.poll(); 25 | if (isOddFloor) { 26 | nums.offerLast(curNode.val); 27 | } else { 28 | nums.offerFirst(curNode.val); 29 | } 30 | if (curNode.left != null) { 31 | queue.add(curNode.left); 32 | } 33 | if (curNode.right != null) { 34 | queue.add(curNode.right); 35 | } 36 | } 37 | isOddFloor = !isOddFloor; 38 | resultList.add(new LinkedList<>(nums)); 39 | } 40 | return resultList; 41 | } 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /LeetCode104. 二叉树的最大深度.md: -------------------------------------------------------------------------------- 1 | # 二叉树的最大深度 2 | >给定一个二叉树,找出其最大深度。 3 | >二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 4 | 5 | >说明: 叶子节点是指没有子节点的节点。 6 | 7 | >示例: 8 | 给定二叉树 [3,9,20,null,null,15,7], 9 | 返回最大深度:3 10 | 11 | 思路分析:深度优先遍历,若还有子节点则继续往下遍历层数+1, 无子结点则返回当前层数,max 记录最大层数 12 | ```java 13 | class Solution { 14 | private int max = 0; 15 | public int maxDepth(TreeNode root) { 16 | maxDepth(root, 0); 17 | return max; 18 | } 19 | 20 | private void maxDepth(TreeNode root, int depth) { 21 | if (root == null) { 22 | max = max < depth ? depth : max; // 记录最大层数 23 | return; 24 | } 25 | maxDepth(root.left, depth+1); // 遍历下一层,层数+1 26 | maxDepth(root.right, depth+1); 27 | } 28 | } 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /LeetCode1046. 最后一块石头的重量.md: -------------------------------------------------------------------------------- 1 | # LeetCode1046. 最后一块石头的重量 2 | 3 | #### [1046. 最后一块石头的重量](https://leetcode-cn.com/problems/last-stone-weight/) 4 | 5 | 解题思路:排序法,基于大顶堆优化排序 6 | 7 | 1、创建优先队列,初始化队列长度为 stones.length,排队策略为从大到小排队(实际就是大顶堆) 8 | 9 | 2、依序遍历 stones 元素,完成优先队列初始化 10 | 11 | 3、循环从 队列中取两个数 x,y ,若仅有一个元素,则返回 y,存在两个元素则进行比较,x,y不相等时,将 y-x 加入队列 12 | 13 | 4、若队列为空结束循环 ,返回 0 14 | 15 | ```java 16 | public int lastStoneWeight(int[] stones) { 17 | PriorityQueue priorityQueue = new PriorityQueue<>(stones.length, (n1, n2) -> n2 - n1); 18 | for (int stone : stones) { 19 | priorityQueue.add(stone); 20 | } 21 | while (!priorityQueue.isEmpty()) { 22 | int y = priorityQueue.poll(); 23 | if (priorityQueue.isEmpty()) { 24 | return y; 25 | } 26 | int x = priorityQueue.poll(); 27 | if (x != y) { 28 | priorityQueue.add(y-x); 29 | } 30 | } 31 | return 0; 32 | } 33 | ``` 34 | 35 | 优化代码,提取出队列仅有1个元素的判断逻辑,仅在队列元素数量大于 1 时进行循环 36 | 37 | ```java 38 | public int lastStoneWeight(int[] stones) { 39 | PriorityQueue priorityQueue = new PriorityQueue<>(stones.length, (n1, n2) -> n2 - n1); 40 | for (int stone : stones) { 41 | priorityQueue.add(stone); 42 | } 43 | while (priorityQueue.size()>1) { 44 | int y = priorityQueue.poll(); 45 | int x = priorityQueue.poll(); 46 | if (y != x) { 47 | priorityQueue.add(y - x); 48 | } 49 | } 50 | return priorityQueue.isEmpty() ? 0 : priorityQueue.poll(); 51 | } 52 | ``` 53 | 54 | -------------------------------------------------------------------------------- /LeetCode1047. 删除字符串中的所有相邻重复项.md: -------------------------------------------------------------------------------- 1 | # LeetCode1047. 删除字符串中的所有相邻重复项 2 | 3 | #### [1047. 删除字符串中的所有相邻重复项](https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/) 4 | 5 | 解题思路: 6 | 7 | 1. 依次遍历 S 元素放入栈中,若当前遍历元素与栈顶元素相等,则栈顶元素出栈 8 | 2. 否,元素入栈 9 | 3. 遍历结束,返回栈内元素 10 | 11 | ```java 12 | public String removeDuplicates(String S) { 13 | Deque stack = new LinkedList<>(); 14 | for (char c : S.toCharArray()) { 15 | if (!stack.isEmpty() && stack.peek() == c) { 16 | stack.pop(); 17 | } else { 18 | stack.push(c); 19 | } 20 | } 21 | StringBuilder result = new StringBuilder(); 22 | while (!stack.isEmpty()) { 23 | result.insert(0, stack.pop()); 24 | } 25 | return result.toString(); 26 | } 27 | ``` 28 | 29 | 代码优化 30 | 31 | ```java 32 | public String removeDuplicates(String S) { 33 | StringBuilder result = new StringBuilder(); 34 | int lastIndex = -1; 35 | for (char c : S.toCharArray()) { 36 | if (lastIndex>=0 && result.charAt(lastIndex) == c) { 37 | result.deleteCharAt(lastIndex--); 38 | } else { 39 | result.insert(++lastIndex, c); 40 | } 41 | } 42 | return result.toString(); 43 | } 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /LeetCode1052. 爱生气的书店老板.md: -------------------------------------------------------------------------------- 1 | # LeetCode1052. 爱生气的书店老板 2 | 3 | #### [1052. 爱生气的书店老板](https://leetcode-cn.com/problems/grumpy-bookstore-owner/) 4 | 5 | 解题思路:滑动窗口 6 | 7 | 1、首次遍历,记录老板不生气时的总客户数 total 8 | 9 | 3、滑动窗口(固定大小为 X)记录每次窗口内老板生气时的顾客数量 sum 10 | 11 | 4、依次更新窗口元素,max 存储滑动窗口最大值 12 | 13 | ```java 14 | public int maxSatisfied(int[] customers, int[] grumpy, int X) { 15 | int total = 0, max = 0; 16 | // 首次遍历,记录老板不生气时的总客户数 total 17 | for (int i = 0; i < customers.length; i++) { 18 | if (grumpy[i] == 0) { 19 | total += customers[i]; 20 | } 21 | } 22 | // 初始化 max 23 | for (int i = 0; i < X; i++) { 24 | if (grumpy[i] == 1) { 25 | max += customers[i]; 26 | } 27 | } 28 | int sum = max; 29 | // 依次更新窗口元素,max 存储滑动窗口最大值 30 | for (int i = X; i < customers.length; i++) { 31 | sum = sum - customers[i - X] * grumpy[i - X] + customers[i] * grumpy[i]; 32 | max = Math.max(max, sum); 33 | } 34 | return total + max; 35 | } 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /LeetCode111. 二叉树的最小深度.md: -------------------------------------------------------------------------------- 1 | # 二叉树的最小深度 2 | >给定一个二叉树,找出其最小深度。 3 | >最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 4 | 5 | >说明: 叶子节点是指没有子节点的节点。 6 | 7 | 注意条件:**叶子节点是指没有子节点的节点** 8 | 9 | 思路分析: 10 | 1. 基于广度优先遍历,每遍历一层我们判断当前结点是否存在左右子结点。 11 | 2. 若不存在,则当前深度为最小深度。 12 | 3. 若存在则继续遍历下一层。 13 | ```java 14 | class Solution { 15 | public int minDepth(TreeNode root) { 16 | if (root == null) { // 根节点,特殊处理 17 | return 0; 18 | } 19 | int depth = 1; // 初始深度为 1 20 | LinkedList queue = new LinkedList<>(); // 存储每一层元素 21 | queue.add(root); 22 | while (queue.size() != 0) { 23 | int size = queue.size(); 24 | for (int i = 0; i < size; i++) { // 遍历每一层 25 | TreeNode temp = queue.poll(); // 取出队顶元素 26 | if (temp.left == null && temp.right == null) { 27 | return depth; // 无结点,则当前节点为叶节点,返回当前层数 28 | } 29 | if (temp.left != null) { // 队列加入左右非空子结点 30 | queue.add(temp.left); 31 | } 32 | if (temp.right != null) { 33 | queue.add(temp.right); 34 | } 35 | } 36 | depth++; 37 | } 38 | return depth; 39 | } 40 | } 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /LeetCode1128.等价多米诺骨牌对的数量.md: -------------------------------------------------------------------------------- 1 | # LeetCode1128.等价多米诺骨牌对的数量 2 | 3 | #### [1128.等价多米诺骨牌对的数量](https://leetcode-cn.com/problems/number-of-equivalent-domino-pairs/) 4 | 5 | 解题思路:参考 [官方题解](https://leetcode-cn.com/problems/number-of-equivalent-domino-pairs/solution/deng-jie-duo-mi-nuo-gu-pai-dui-de-shu-li-yjlz/) 6 | 7 | 1、总对数计算规则:第 N 次出现等价多米诺骨牌,增加的对的数量为 n (注:[1,2],[2,1] 为 1次出现) 8 | 9 | 2、多米诺骨牌二维坐标转一维坐标,转换方式: dominoe[0] * 9 + dominoe[1], dominoe[0]、dominoe[1] 分别代表横纵坐标较大者 10 | 11 | 3、因为 1 <= dominoes\[i]\[j] <= 9,所以将二维坐标转换为一维坐标后 [2,90]可以表示所有坐标 12 | 13 | 4、count[] 记录每对多米诺骨牌出现次数 14 | 15 | 5、每遍历一张多米诺骨牌 总最对数+=result += count[index],同时更新count[index] 16 | 17 | ```java 18 | public int numEquivDominoPairs(int[][] dominoes) { 19 | // 多米诺骨牌二维坐标转一维坐标 20 | int[] count = new int[91]; 21 | // 总最对数 22 | int result = 0; 23 | // 遍历多米诺骨牌 24 | for (int[] dominoe : dominoes) { 25 | int index = dominoe[0] > dominoe[1] ? dominoe[0] * 9 + dominoe[1] : dominoe[1] * 9 + dominoe[0]; 26 | result += count[index]; 27 | count[index]++; 28 | } 29 | return result; 30 | } 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /LeetCode1162. 地图分析.md: -------------------------------------------------------------------------------- 1 | # 1162. 地图分析 2 | 解题思路:动态规划 3 | 4 | 1、当前坐标距离为上下左右距离最小值+1 5 | 6 | 2、两次距离计算,第一次以上左为参照,第二次以下右为参照,如果是陆地标记为 0 7 | 8 | 3、maxDistance 记录最大距离 9 | 10 | ```java 11 | public int maxDistance(int[][] grid) { 12 | int maxDistance = -1; 13 | int[][] distance = new int[grid.length][grid[0].length]; 14 | // 初始化 15 | for (int[] ints : distance) { 16 | Arrays.fill(ints, Integer.MAX_VALUE-1); 17 | } 18 | // 第一次距离计算,以上左为参照,是陆地则初始化为 1 19 | for (int i = 0; i < grid.length; i++) { 20 | for (int j = 0; j < grid[i].length; j++) { 21 | if (grid[i][j] == 1) { 22 | distance[i][j] = 0; 23 | continue; 24 | } 25 | if (i - 1 >= 0) { 26 | distance[i][j] = Math.min(distance[i][j], distance[i - 1][j] + 1); 27 | } 28 | if (j - 1 >= 0) { 29 | distance[i][j] = Math.min(distance[i][j], distance[i][j - 1] + 1); 30 | } 31 | } 32 | } 33 | // 第二次距离计算,以右下为参照,同时更新最大 maxDistance 34 | for (int i = grid.length - 1; i >= 0; i--) { 35 | for (int j = grid[0].length - 1; j >= 0; j--) { 36 | if (grid[i][j] == 1) { 37 | continue; 38 | } 39 | if (i + 1 < grid.length) { 40 | distance[i][j] = Math.min(distance[i][j], distance[i + 1][j] + 1); 41 | } 42 | if (j + 1 < grid[i].length) { 43 | distance[i][j] = Math.min(distance[i][j], distance[i][j + 1] + 1); 44 | } 45 | maxDistance = Math.max(distance[i][j], maxDistance); 46 | } 47 | } 48 | // 对于全为海洋情况进行特殊处理 49 | return maxDistance == Integer.MAX_VALUE - 1 ? -1 : maxDistance; 50 | } 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /LeetCode118. 杨辉三角.md: -------------------------------------------------------------------------------- 1 | # LeetCode118. 杨辉三角 2 | 3 | [LeetCode 118. 杨辉三角](https://leetcode-cn.com/problems/pascals-triangle/) 4 | 5 | ```java 6 | /** 7 | * 规律:第 N 行有 N 个元素,每行起始和末尾元素都为 1,第二行开始第 n 个元素=上一行第N-1 + 第 N-1个 8 | */ 9 | public List> generateOne(int numRows) { 10 | List> resultList = new ArrayList<>(); 11 | if (numRows == 0) { 12 | return resultList; 13 | } 14 | // 初始化第一行 15 | resultList.add(Arrays.asList(1)); 16 | for (int i = 1; i < numRows; i++) { 17 | Integer[] line = new Integer[i + 1]; 18 | line[0] = 1; 19 | line[line.length - 1] = 1; 20 | for (int j = 1; j < i; j++) { 21 | line[j] = resultList.get(i - 1).get(j - 1) + resultList.get(i - 1).get(j); 22 | } 23 | resultList.add(Arrays.asList(line)); 24 | } 25 | return resultList; 26 | } 27 | ``` 28 | 29 | 优化后: 30 | 31 | ```java 32 | public List> generate(int numRows) { 33 | List> resultList = new ArrayList<>(numRows); 34 | for (int rowNum = 0; rowNum < numRows; rowNum++) { 35 | List line = new ArrayList<>(rowNum+1); 36 | for (int colNum = 0; colNum <= rowNum; colNum++) { 37 | // 首、尾元素特殊处理 38 | if (colNum == 0 || colNum == rowNum) { 39 | line.add(1); 40 | } else { 41 | line.add(resultList.get(rowNum - 1).get(colNum - 1) + resultList.get(rowNum - 1).get(colNum)); 42 | } 43 | } 44 | resultList.add(line); 45 | } 46 | return resultList; 47 | } 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /LeetCode12. 整数转罗马数字.md: -------------------------------------------------------------------------------- 1 | # 整数转罗马数字 [题目链接](https://leetcode-cn.com/problems/integer-to-roman/) 2 | 3 | > 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 4 | > 字符 数值 I 1 V 5 X 10 L 5 | > 50 C 100 D 500 M 1000 例如, 罗马数字 2 6 | > 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。 7 | 8 | > 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 9 | > 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况: 10 | 11 | > I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。 X 可以放在 L (50) 和 C (100) 的左边,来表示 12 | > 40 和 90。 C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。 13 | > 给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。 14 | 15 | > 示例 1: 16 | > 输入: 3 输出: "III" 17 | 18 | 解题思路: 19 | 从最高位开始转换罗马数 20 | 根据高位转化后的余数转换成罗马字符 21 | ```java 22 | class Solution { 23 | public String intToRoman(int num) { 24 | String romanNum = ""; 25 | int[] key={1000,900,500,400,100,90,50,40,10,9,5,4,1}; 26 | String[] value={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"}; 27 | int shang=0; 28 | for(int i=0;i0){ 35 | romanNum+=value[i]; 36 | shang--; 37 | } 38 | num%=key[i]; 39 | } 40 | } 41 | return romanNum; 42 | } 43 | } 44 | ``` 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /LeetCode120. 三角形最小路径和.md: -------------------------------------------------------------------------------- 1 | # 三角形最小路径和 2 | >给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 3 | 4 | >例如,给定三角形: 5 | [ 6 | [2], 7 | [3,4], 8 | [6,5,7], 9 | [4,1,8,3] 10 | ] 11 | 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 12 | 13 | >来源:力扣(LeetCode) 14 | 链接:https://leetcode-cn.com/problems/triangle 15 | 16 | 思路分析:动态规划,自底向上看。 17 | 1. 当前路径的最小值,为下一层左右两点的最小值加上当前坐标值 18 | 2. 状态转移方程:min[row][col]=min(min[row+1][col],min[row][col+1])+triangle[row][col] 19 | 20 | 21 | ```java 22 | class Solution { 23 | public int minimumTotal(List> triangle) { 24 | if (triangle == null || triangle.size() == 0) { 25 | return 0; // 处理空指针异常 26 | } 27 | int len = triangle.get(triangle.size() - 1).size(); // 最底层数据长度 28 | int[] result = new int[len]; // 存储下一层结果 29 | for (int i = 0; i < len; i++) { // 初始化最底层数据 30 | result[i] = triangle.get(triangle.size() - 1).get(i); 31 | } 32 | for (int row = triangle.size()-2; row >=0 ; row--) { 33 | for (int col = 0; col < triangle.get(row).size(); col++) { 34 | // 状态转移方程:min[row][col]=min(min[row+1][col],min[row][col+1])+triangle[row][col] 35 | result[col] = triangle.get(row).get(col) + Math.min(result[col], result[col + 1]); 36 | } 37 | } 38 | return result[0]; 39 | } 40 | } 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /LeetCode1208. 尽可能使字符串相等.md: -------------------------------------------------------------------------------- 1 | # LeetCode1208. 尽可能使字符串相等 2 | 3 | #### [1208. 尽可能使字符串相等](https://leetcode-cn.com/problems/get-equal-substrings-within-budget/) 4 | 5 | 解题思路:滑动窗口 6 | 7 | 1、maxLen 记录最大可转换长度,left、right 分别记录当前窗口左边界与右边界 8 | 9 | 2、cost 为当前滑动窗口剩余预算 10 | 11 | 3、依序遍历 s 元素,当 cost- Math.abs(s.charAt(right) - t.charAt(right)) 12 | 13 | 4、若 cost < 0 说明此时无法转换右边界字符,则滑动串口左边界右移,cost+=Math.abs(s.charAt(left) - t.charAt(left)),直到 cost>=0 (即满足条件转换有边界字符) 14 | 15 | 5、若 cost >= 0 直接更新右边界,同时更新 maxLen 记录最大可转换长度 16 | 17 | ```java 18 | public int equalSubstring(String s, String t, int maxCost) { 19 | int maxLen = 0; 20 | int left = 0, right = 0, cost = maxCost; 21 | while (right < s.length()) { 22 | int needCost = Math.abs(s.charAt(right) - t.charAt(right)); 23 | cost -= needCost; 24 | while (cost < 0) { 25 | cost += Math.abs(s.charAt(left) - t.charAt(left)); 26 | left++; 27 | } 28 | right++; 29 | maxLen = Math.max(right - left, maxLen); 30 | } 31 | return maxLen; 32 | } 33 | ``` 34 | 35 | 优化:避免重复计算 s[i]-t[i] 差值,初始化[] diff 存储每一位差值 36 | 37 | ```java 38 | public int equalSubstring(String s, String t, int maxCost) { 39 | int maxLen = 0; 40 | int left = 0, right = 0, cost = maxCost; 41 | int[] diff = new int[s.length()]; 42 | for (int i = 0; i < s.length(); i++) { 43 | diff[i] = Math.abs(s.charAt(i) - t.charAt(i)); 44 | } 45 | while (right < s.length()) { 46 | int needCost = diff[right]; 47 | cost -= needCost; 48 | while (cost < 0) { 49 | cost += diff[left]; 50 | left++; 51 | } 52 | right++; 53 | maxLen = Math.max(right - left, maxLen); 54 | } 55 | return maxLen; 56 | } 57 | ``` 58 | 59 | -------------------------------------------------------------------------------- /LeetCode121. 买卖股票的最佳时机.md: -------------------------------------------------------------------------------- 1 | # 买卖股票的最佳时机 2 | >给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 3 | 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 4 | 5 | >注意你不能在买入股票前卖出股票。 6 | 7 | >示例 1: 8 | 输入: [7,1,5,3,6,4] 9 | 输出: 5 10 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 11 | 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 12 | 13 | >来源:力扣(LeetCode) 14 | 链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock 15 | 16 | 思路分析:当前收益最大值 = 当前股价 - 前期最低买入股价(或不买) 17 | 18 | min 记录前面的最小值,max 存储当前数减去最小值的最大值 19 | 20 | ```java 21 | class Solution { 22 | public int maxProfit(int[] prices) { 23 | // 处理空指针异常 24 | if (prices == null || prices.length < 1) { 25 | return 0; 26 | } 27 | int min = prices[0], max = 0; 28 | for (int i = 1; i < prices.length; i++) { 29 | int money = prices[i] - min; // 当前卖出最大值 30 | max = max < money ? money : max; // 更新最大值 31 | min = min > prices[i] ? prices[i] : min; // 更新最小值 32 | } 33 | return max; 34 | } 35 | } 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /LeetCode122. 买卖股票的最佳时机 II.md: -------------------------------------------------------------------------------- 1 | # 买卖股票的最佳时机 II 2 | >给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 3 | >设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 4 | >注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 5 | 6 | >示例 1: 7 | 输入: [7,1,5,3,6,4] 8 | 输出: 7 9 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 10 | 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 11 | 12 | >来源:力扣(LeetCode) 13 | 链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii 14 | 15 | 思路分析:如果后一天比前一天价格高则 当天买入,第二天卖出,加上每一笔利润、返回 16 | 17 | ```java 18 | public int maxProfit(int[] prices) { 19 | if (prices == null || prices.length < 2) { 20 | return 0; // 无法盈利 21 | } 22 | int money = 0; 23 | for (int i = 0; i < prices.length-1; i++) { 24 | if (prices[i] < prices[i + 1]) { 25 | money += prices[i + 1] - prices[i]; // 当天买入,第二天卖出 26 | } 27 | } 28 | return money; 29 | } 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /LeetCode1232.缀点成线.md: -------------------------------------------------------------------------------- 1 | # LeetCode1232.缀点成线 2 | 3 | #### [1232. 缀点成线](https://leetcode-cn.com/problems/check-if-it-is-a-straight-line/) 4 | 5 | 解题思路:已知直线 ( x,y ) 关系可表示为 y=kx+b 6 | 7 | 特殊情况:直线与 x 轴垂直 8 | 9 | 1、处理特殊情况,当 coordinates\[0]\[0] == coordinates\[1]\[0],后续所有点的 x 坐标都必须恒等于 coordinates\[1]\[0] 10 | 11 | 2、通过 coordinates\[0],coordinates\[1] 计算出 k 和 b,后续所有坐标都必须满足该表达式才能在同一直线 12 | 13 | ```java 14 | public boolean checkStraightLine(int[][] coordinates) { 15 | // 处理特殊情况 16 | if (coordinates[0][0] == coordinates[1][0]) { 17 | for (int i = 2; i < coordinates.length; i++) { 18 | if (coordinates[i][0] != coordinates[0][0]) { 19 | return false; 20 | } 21 | } 22 | return true; 23 | } 24 | // 计算出 k 和 b 25 | double k = (coordinates[0][1] - coordinates[1][1]) / (1.0*(coordinates[0][0] - coordinates[1][0])); 26 | int b = coordinates[0][1] - (int) (k * coordinates[0][0]); 27 | // 判断后续坐标点是否满足表达式 28 | for (int i = 1; i < coordinates.length; i++) { 29 | if (k * coordinates[i][0] + b != coordinates[i][1]) { 30 | return false; 31 | } 32 | } 33 | return true; 34 | } 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /LeetCode124. 二叉树中的最大路径和.md: -------------------------------------------------------------------------------- 1 | # 124. 二叉树中的最大路径和 [题目链接](https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/) 2 | 解题思路:当前节点最大路径值=Max(左子树最大路径值,右子树最大路径值)+当前节点值 3 | 4 | 若左右子树最大路径值为负数,则不加上子树路径值(子树路劲值设为 0) 5 | 6 | 以后序遍历顺序依次计算每一节点路径值,max 存储最大值即可 7 | 8 | ```java 9 | private int maxPath = Integer.MIN_VALUE; 10 | public int maxPathSum(TreeNode root) { 11 | postOrder(root); 12 | return maxPath; 13 | } 14 | 15 | private int postOrder(TreeNode root) { 16 | if (root == null) { 17 | return 0; 18 | } 19 | int left = Math.max(0, postOrder(root.left)); 20 | int right = Math.max(0, postOrder(root.right)); 21 | maxPath = Math.max(maxPath, right + left + root.val); 22 | return Math.max(right, left) + root.val; 23 | } 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /LeetCode14. 最长公共前缀.md: -------------------------------------------------------------------------------- 1 | # 最长公共前缀 [题目链接](https://leetcode-cn.com/problems/longest-common-prefix/) 2 | 3 | > 编写一个函数来查找字符串数组中的最长公共前缀。 4 | > 如果不存在公共前缀,返回空字符串 ""。 5 | 6 | > 示例 1: 7 | > 输入: ["flower","flow","flight"] 输出: "fl" 8 | 9 | 解题思路: 10 | 11 | 1. 先考虑特殊情况:strs 为空或只有 1 个字符,则返回 "" 或 strs[0] 。 12 | 2. 以str[0] 字符串长度为基准,依序遍历字符串数组字符。 13 | 3. 若当前遍历字符串字符与上一字符串字符不同或已遍历当前字符串末尾则结束匹配,返回公共前缀。 14 | 15 | ```java 16 | class Solution { 17 | public String longestCommonPrefix(String[] strs) { 18 | int len = strs.length; // 存储字符串数组长度 19 | if(len==0){ // 过滤特殊情况 20 | return ""; 21 | } 22 | else if(len==1){ 23 | return strs[0]; 24 | } 25 | 26 | int lenStr1=strs[0].length(); // 存储字符串数组第一条字符串长度 27 | int i=0; // 匹配字符索引 28 | int j=1; // strs 字符串数组索引 29 | while(i=strs[j].length()||strs[j].charAt(i)!=strs[j-1].charAt(i)){ // 无法构成公共前缀则结束遍历 31 | break; 32 | } 33 | else{ 34 | j++; 35 | } 36 | if(j==len){ 37 | i++; 38 | j=1; 39 | } 40 | } 41 | return strs[0].substring(0,i); // 返回公共前缀 42 | } 43 | } 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /LeetCode1423. 可获得的最大点数.md: -------------------------------------------------------------------------------- 1 | # LeetCode1423. 可获得的最大点数 2 | 3 | #### [1423. 可获得的最大点数](https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards/) 4 | 5 | 解题思路:正难则反,剩余元素之和最小时,拿走的纸牌之和最大 6 | 7 | 1. 一次遍历,计算 cardPoints 元素之和 8 | 2. 滑动窗口,slideSum 存储窗口元素之和,minSum 存储窗口最小值,窗口大小为 cardPoints.length-k 9 | 3. 滑动窗口每次移出 cardPoints[left],加入 cardPoints[right+1] 10 | 11 | ```java 12 | public int maxScore(int[] cardPoints, int k) { 13 | int left = 0, right = 0, cardSum = 0, slideLen = cardPoints.length - k; 14 | for (int cardPoint : cardPoints) { 15 | cardSum += cardPoint; 16 | } 17 | // 窗口长度为 0,所有纸牌都被拿出 18 | if (slideLen == 0) { 19 | return cardSum; 20 | } 21 | int slideSum = 0, minSum = Integer.MAX_VALUE; 22 | while (right < cardPoints.length) { 23 | slideSum += cardPoints[right++]; 24 | if (right - left < slideLen) { 25 | continue; 26 | } 27 | minSum = Math.min(slideSum, minSum); 28 | slideSum -= cardPoints[left++]; 29 | } 30 | return cardSum - minSum; 31 | } 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /LeetCode151. 翻转字符串里的单词.md: -------------------------------------------------------------------------------- 1 | # 151. 翻转字符串里的单词 [题目链接](https://leetcode-cn.com/problems/reverse-words-in-a-string/) 2 | 解法一:去除字符串首尾空格,从尾部开始遍历字符串 3 | 4 | ```java 5 | public String reverseWords(String s) { 6 | if (s == null || s.length() < 1) { 7 | return s; 8 | } 9 | char[] str = s.trim().toCharArray(); 10 | StringBuilder newStr = new StringBuilder(str.length); 11 | int index = str.length - 1; 12 | while (index >= 0) { 13 | while (index >= 0 && str[index] == ' ') { 14 | index--; 15 | } 16 | int start = index; 17 | while (start > 0 && str[start - 1] != ' ') { 18 | start--; 19 | } 20 | newStr.append(Arrays.copyOfRange(str, start, index)); 21 | newStr.append(" "); 22 | index = start - 1; 23 | } 24 | if (newStr.length() > 0) { 25 | newStr.deleteCharAt(newStr.length() - 1); 26 | } 27 | return newStr.toString(); 28 | } 29 | ``` 30 | 解法二:去除字符串首尾空格,正则表达式匹配多个空格,切分字符串,倒序加入切分字符 31 | 32 | ```java 33 | class Solution { 34 | public String reverseWords(String s) { 35 | if (s == null || s.length() < 1) { 36 | return s; 37 | } 38 | String str = s.trim(); 39 | String[] strs = str.split("\\s+"); 40 | StringBuilder newStr = new StringBuilder(str.length()); 41 | for (int i = strs.length - 1; i >= 0; i--) { 42 | newStr.append(strs[i] + " "); 43 | } 44 | if (newStr.length() > 0) { 45 | newStr.deleteCharAt(newStr.length() - 1); 46 | } 47 | return newStr.toString(); 48 | } 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /LeetCode153. 寻找旋转排序数组中的最小值.md: -------------------------------------------------------------------------------- 1 | # LeetCode153. 寻找旋转排序数组中的最小值 2 | 3 | #### [153. 寻找旋转排序数组中的最小值](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/) 4 | 5 | 解题思路:二分查找,当 num[mid] 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 4 | 5 | >例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 6 | >与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). 7 | 8 | 思路分析: 9 | 10 | 对 nums 排序,再依序遍历 nums 数组中的每个数,为固定数 fix,与剩余数组合计算与 target 的差值。 11 | 12 | 剩下两数从 nums 剩余元素中组合(索引范围 fixIndex+1~len-1 ),start 从 fixIndex+1 开始,end 从 len-1 开始 13 | 14 | 计算与 target 的差值,可能出现的情况有 3 种 15 | 16 | 1、差值为 0 ,说明已找到正确组合,则直接返回 target 17 | 18 | 2、差值 <0 , 则增加三数和,start 索引+1 19 | 20 | 3、差值 >0 , 则减小三数和,end 索引-1 21 | 22 | sub 存储与 target 最小差值 23 | ```java 24 | class Solution { 25 | public int threeSumClosest(int[] nums, int target) { 26 | int sum = 0; 27 | int len = nums.length; 28 | if (len == 3) { // 若 nums 只有 3 个数则直接返回三数之和 29 | return nums[0] + nums[1] + nums[2]; 30 | } 31 | Arrays.sort(nums); // 将nums 降序排序 32 | int start = 0; 33 | int end = len - 1; 34 | double sub = Integer.MAX_VALUE; // 存储最小差值,定义 double 类型防止运算后超出 int 类型取值范围 35 | int fixIndex = 0; 36 | for (int i = 0; i < len-2; i++) { 37 | fixIndex = i; 38 | start=i+1; 39 | end=len-1; 40 | while (start < end) { 41 | sum = nums[start] + nums[fixIndex] + nums[end] - target; // 三数和与 target 差值 42 | if (sum == 0) { // 若新组合三数与 target 相等则直接返回 target 43 | return target; 44 | } 45 | sub = Math.abs(sub) > Math.abs(sum) ? sum : sub; // sub 存储最小与 target 最小差值 46 | if (sum > 0) { 47 | end--; 48 | } else { 49 | start++; 50 | } 51 | } 52 | } 53 | return (int) (target + sub); // 返回差值与 target 之和 54 | } 55 | } 56 | ``` 57 | 58 | -------------------------------------------------------------------------------- /LeetCode18. 四数之和.md: -------------------------------------------------------------------------------- 1 | # 四数之和 [题目链接](https://leetcode-cn.com/problems/4sum/) 2 | 3 | > 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + 4 | > b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 5 | 6 | > 注意: 7 | > 答案中不可以包含重复的四元组。 8 | 9 | 解题思路: 10 | 11 | 1. 在三数之和的思路上修改,首先是对数组进行排序,将 nums 升序排序 12 | 2. 先选取 nums 中的一个数(第一层外循环),再在剩余数中选取第二个数(第二层循环) 剩余两个数分别从剩余数的最小端 left 、最大端 right扫描数组 13 | 3. 当四数之和与 target 相等时 ,加入当前四数组合,继续查找下一四数组合。(HashSet 去除重复项) 14 | 4. 若大于 target ,则 right 向左端扫描 15 | 5. 若小于 target ,则 left 向右端扫描 16 | 17 | ```java 18 | public List> fourSum(int[] nums, int target) { 19 | List> lists = new ArrayList<>(); 20 | HashSet> map=new HashSet<>(lists); 21 | int len=nums.length; 22 | Arrays.sort(nums); 23 | for(int i=0;i list = new ArrayList<>() ; 31 | list.add(nums[i]);list.add(nums[j]);list.add(nums[left]);list.add(nums[right]); 32 | map.add(list); // 用哈希表去重,将匹配的四数集合放入 map 33 | left++; 34 | right--; 35 | continue; // 继续查找下一可能组合 36 | } 37 | else if(sum>target){ 38 | right--; // 减小四数和 39 | } 40 | else { 41 | left++; // 增大四数和 42 | } 43 | } 44 | } 45 | } 46 | lists.addAll(map); // 将所有非重复结果加入 lists 47 | return lists; 48 | } 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /LeetCode189. 旋转数组.md: -------------------------------------------------------------------------------- 1 | # LeetCode189. 旋转数组 2 | 3 | #### [189. 旋转数组](https://leetcode-cn.com/problems/rotate-array/) 4 | 5 | 解法一:额外数组 6 | 7 | 思路:将右移操作看为,截取数据 [k,nums.length-1] 拼接至数据首部 8 | 9 | ```java 10 | public void rotate(int[] nums, int k) { 11 | int len = nums.length; 12 | // 获取实际要右移长度 13 | k = k % len; 14 | int[] temp = new int[k]; 15 | // 暂存末尾 k 个数字 16 | for (int i = 0; i < k; i++) { 17 | temp[i] = nums[len - k + i]; 18 | } 19 | // 右移剩余数字 20 | for (int i = len - 1; i >= k; i--) { 21 | nums[i] = nums[i - k]; 22 | } 23 | // 拼接至数组首部 24 | for (int i = 0; i < k; i++) { 25 | nums[i] = temp[i]; 26 | } 27 | } 28 | ``` 29 | 30 | 解法二:翻转数组,[参考官方题解](https://leetcode-cn.com/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/) 31 | 32 | 思路:将右移操作看为 3 次翻转。先翻转整个数组,再分别翻转[0,k-1]、[k,nums.length-1] 33 | 34 | ```java 35 | public void rotate(int[] nums, int k) { 36 | int len = nums.length; 37 | // 获取实际要右移长度 38 | k = k % len; 39 | reverse(nums, 0, len - 1); 40 | reverse(nums, 0, k - 1); 41 | reverse(nums, k, len - 1); 42 | } 43 | 44 | private void reverse(int[] nums, int start, int end) { 45 | while (start < end) { 46 | int temp = nums[start]; 47 | nums[start++] = nums[end]; 48 | nums[end--] = temp; 49 | } 50 | } 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /LeetCode19. 删除链表的倒数第N个节点.md: -------------------------------------------------------------------------------- 1 | # 删除链表的倒数第N个节点 [题目链接](https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/submissions/) 2 | 3 | > 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。 4 | 5 | > 示例: 6 | > 给定一个链表: 1->2->3->4->5, 和 n = 2. 7 | 8 | > 当删除了倒数第二个节点后,链表变为 1->2->3-5. 9 | 10 | 双指针法解题思路: 11 | - node 指针指向头结点,fast 指针指向 node 后的第 n+1 个结点 12 | - 双指针同时向后遍历,当 fast 遍历至链尾时, node 指针指向下一结点的下一结点即可 13 | - 特殊情况,要删除的结点为头结点,即 fast 在定义时就遍历至链尾,则返回头结点的下一结点即可 14 | 15 | ```java 16 | public ListNode removeNthFromEnd(ListNode head, int n) { 17 | ListNode node=head; 18 | ListNode fast=head.next; 19 | for(int i=0;i编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 3 | 4 | >示例 1: 5 | 输入:00000000000000000000000000001011 6 | 输出:3 7 | 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 8 | 9 | >来源:力扣(LeetCode) 10 | 链接:https://leetcode-cn.com/problems/number-of-1-bits 11 | 12 | 思路分析:利用 & 运算技巧,只有二进制位同时为 1 时,运算结果为 1, x&(x-1) 从右至左消除二进制 1 13 | ```java 14 | public class Solution { 15 | // 利用二进制 x&(x-1) 从右至左消除二进制 1 16 | public int hammingWeight(int n) { 17 | int count = 0; 18 | while (n != 0) { // 消除所有 1,归零 19 | n &= n - 1; 20 | count++; 21 | } 22 | return count; 23 | } 24 | } 25 | ``` 26 | 27 | 28 | -------------------------------------------------------------------------------- /LeetCode202.快乐数.md: -------------------------------------------------------------------------------- 1 | # 快乐数 2 | >编写一个算法来判断一个数是不是“快乐数”。 3 | 一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。 4 | 5 | >示例: 6 | 输入: 19 7 | 输出: true 8 | 解释: 9 | 12 + 92 = 82 10 | 82 + 22 = 68 11 | 62 + 82 = 100 12 | 12 + 02 + 02 = 1 13 | 14 | >来源:力扣(LeetCode) 15 | 链接:https://leetcode-cn.com/problems/happy-number 16 | 17 | 解题思路:set 记录已计算数字,当出现重复数字时说明不是快乐数(一直在进行死循环),否,为快乐数,因为会枚举到 1 的结果。 18 | 19 | ```java 20 | public boolean isHappy(int n) { 21 | HashSet set = new HashSet<>(); 22 | set.add(n); 23 | while (n != 1) { 24 | int sum = 0; 25 | while (n != 0) { 26 | sum += (n % 10) * (n % 10); 27 | n /= 10; 28 | } 29 | if (set.contains(sum)) { 30 | return false; 31 | } 32 | n = sum; 33 | set.add(sum); 34 | } 35 | return true; 36 | } 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /LeetCode204. 计数质数.md: -------------------------------------------------------------------------------- 1 | # 计数质数 [题目链接](https://leetcode-cn.com/problems/count-primes/) 2 | >统计所有小于非负整数 n 的质数的数量。 3 | 4 | >示例: 5 | 输入: 10 6 | 输出: 4 7 | 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 8 | 9 | 方法一:isPrimeNumber 判断是否为质数,遍历 【2-n】出现质数则 count+1,遍历结束返回 count 10 | 11 | ```java 12 | public int countPrimes(int n) { 13 | if (n <= 2) { 14 | return 0; 15 | } 16 | int count = 1; 17 | for (int i = 3; i < n; i++) { 18 | count = isPrimeNumber(i) ? count + 1 : count; 19 | } 20 | return count; 21 | } 22 | 23 | private boolean isPrimeNumber(int n){ 24 | int sqrt = (int)Math.sqrt(n)+1; 25 | for (int i = 2; i <= sqrt ; i++) { 26 | if (n % i == 0) { 27 | return false; 28 | } 29 | } 30 | return true; 31 | } 32 | ``` 33 | 方法二:set 记录【2-n】 中两个数所有乘积组合(小于 n),若 【2-n】 中未在 set 中则为质数 34 | 35 | ```java 36 | public int countPrimes(int n) { 37 | if (n <= 2) { 38 | return 0; 39 | } 40 | boolean[] isPrim = new boolean[n]; 41 | Arrays.fill(isPrim, true); 42 | for (int i = 2; i < n; i++) { 43 | for (int j = 2; j*i < n; j++) { // 最小乘积组合 2*2 44 | isPrim[j * i] = false; 45 | } 46 | } 47 | int count = 0; 48 | for (int i = 2; i < n; i++) { // 统计所有质数 49 | if (isPrim[i]) { 50 | count++; 51 | } 52 | } 53 | return count; 54 | } 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /LeetCode205. 同构字符串.md: -------------------------------------------------------------------------------- 1 | # LeetCode205. 同构字符串 2 | 3 | #### [205. 同构字符串](https://leetcode-cn.com/problems/isomorphic-strings/) 4 | 5 | 解题思路:双哈希表法 6 | 7 | 1、遍历 s、t 字符,哈希表 map1 以 s 遍历字符为 key, t 遍历字符为 value;哈希表 map2 以 t 遍历字符为 key, s 遍历字符为 value 8 | 9 | 2、若 s 当前遍历字符字符在 map1 已出现且对应 value 不等于 t 当前 遍历字符,返回 false 10 | 11 | 3、若 t 当前遍历字符字符在 map2 已出现且对应 value 不等于 s 当前 遍历字符,返回 false 12 | 13 | 3、s、t 正常遍历结束,返回 true 14 | 15 | ```java 16 | public boolean isIsomorphic(String s, String t) { 17 | Map map1 = new HashMap<>(26); 18 | Map map2 = new HashMap<>(26); 19 | for (int i = 0; i < s.length(); i++) { 20 | char sChar = s.charAt(i); 21 | char tChar = t.charAt(i); 22 | if ((map1.containsKey(sChar) && map1.get(sChar) != tChar) || 23 | (map2.containsKey(tChar) && map2.get(tChar) != sChar)) { 24 | return false; 25 | } 26 | map1.put(sChar, tChar); 27 | map2.put(tChar, sChar); 28 | } 29 | return true; 30 | } 31 | ``` 32 | 33 | 优化,参考思路:[[C++/Java] 高效写法](https://leetcode-cn.com/problems/isomorphic-strings/solution/c-gao-xiao-xie-fa-by-francissoft-le3k/) 使用 128 位数组表示代替哈希表存储 s、t 映射关系 34 | 35 | ```java 36 | public boolean isIsomorphic(String s, String t) { 37 | int[] map1 = new int[128]; 38 | int[] map2 = new int[128]; 39 | for (int i = 0; i < s.length(); i++) { 40 | char sChar = s.charAt(i); 41 | char tChar = t.charAt(i); 42 | if (map1[sChar]!=map2[tChar]) { 43 | return false; 44 | } 45 | map1[sChar] = map2[tChar] = i + 1; 46 | } 47 | return true; 48 | } 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /LeetCode22. 括号生成.md: -------------------------------------------------------------------------------- 1 | # 22. 括号生成 [题目链接](https://leetcode-cn.com/problems/generate-parentheses/) 2 | 解题思路:创建组合原理,先放左括号,再放右括号,左括号数不能超过 n,右括号数要与右括号数一致 3 | 4 | ```java 5 | public List generateParenthesis(int n) { 6 | List list = new ArrayList<>(); 7 | backList(list, "",0,0,n); 8 | return list; 9 | } 10 | /** 11 | * @param list 12 | * @param str 组合 13 | * @param left 左括号数量 14 | * @param right 右括号数量 15 | * @param max 括号对数 16 | */ 17 | private void backList(List list,String str,int left,int right,int max){ 18 | if(str.length()==max*2){ 19 | list.add(str); 20 | return; 21 | } 22 | if (left < max) { 23 | backList(list, str+"(", left + 1, right, max); 24 | } 25 | if (right < left) { 26 | backList(list,str+")",left,right+1,max); 27 | } 28 | } 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /LeetCode228. 汇总区间.md: -------------------------------------------------------------------------------- 1 | # LeetCode228. 汇总区间 2 | 3 | #### [228. 汇总区间](https://leetcode-cn.com/problems/summary-ranges/) 4 | 5 | 解题思路:一次遍历。若相邻元素差值不为 1 则分成两个区间;差值为1,则合为同一区间 6 | 7 | ```java 8 | public List summaryRanges(int[] nums) { 9 | List resultList = new ArrayList<>(); 10 | int index = 0; 11 | while (index < nums.length) { 12 | StringBuilder range = new StringBuilder(); 13 | range.append(nums[index]); 14 | int end = index + 1; 15 | while (end < nums.length) { 16 | if (nums[end] - nums[end - 1] != 1) { 17 | break; 18 | } 19 | end++; 20 | } 21 | if (end - 1 != index) { 22 | range.append("->"+nums[end - 1]); 23 | } 24 | index = end; 25 | resultList.add(range.toString()); 26 | } 27 | return resultList; 28 | } 29 | ``` 30 | 31 | 32 | -------------------------------------------------------------------------------- /LeetCode231. 2的幂.md: -------------------------------------------------------------------------------- 1 | # 2的幂 2 | >给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 3 | 4 | >示例 1: 5 | 输入: 1 6 | 输出: true 7 | 解释: 20 = 1 8 | 9 | 思路分析: 10 | 1. 挖掘 2 的幂次方数特点,二进制位有且仅有 1 个 1 11 | 2. 基于 191 题,统计 1 的个数,若不止 1 个 1 返回 fasle 12 | ```java 13 | class Solution { 14 | // 2 的幂次方数特点,二进制位有且仅有 1 个 1 15 | // 基于 191 题,统计 1 的个数,若不止 1 个 1 返回 fasle 16 | public boolean isPowerOfTwo(int n) { 17 | if (n == 0 || n == Integer.MIN_VALUE) { 18 | return false; // 处理边界值 19 | } 20 | return (n&(n-1))==0; // 判断二进制位 1个数,是否为 1 21 | } 22 | } 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /LeetCode235. 二叉搜索树的最近公共祖先.md: -------------------------------------------------------------------------------- 1 | # 二叉搜索树的最近公共祖先 2 | >给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 3 | 4 | >示例 1: 5 | >输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 6 | >输出: 6 7 | >解释: 节点 2 和节点 8 的最近公共祖先是 6。 8 | >来源:力扣(LeetCode) 9 | >链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree 10 | 11 | 首先要理解二叉搜索树特点:大于根节点的都在右子树,小于根节点的都在左子树 12 | 13 | 思路分析: 14 | 1. 若 p/q 位于 root 两侧,则根节点为公共祖先 15 | 2. 若都位于左侧,则公共结点出现在左子树 16 | 3. 若都位于右侧,则公共结点出现在右子树 17 | ```java 18 | class Solution { 19 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 20 | // 根节点为公共祖先 21 | if (root == null ||root.val==p.val||root.val==q.val|| 22 | (root.val > p.val && root.val < q.val) || 23 | (root.val < p.val && root.val > q.val)) { 24 | return root; 25 | } 26 | // 都位于左侧,则公共结点出现在左子树 27 | if (p.val < root.val) { 28 | return lowestCommonAncestor(root.left, p, q); 29 | } 30 | // 都位于右侧,则公共结点出现在右子树 31 | return lowestCommonAncestor(root.right, p, q); 32 | } 33 | } 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /LeetCode24. 两两交换链表中的节点.md: -------------------------------------------------------------------------------- 1 | # 两两交换链表中的节点 [题目链接](https://leetcode-cn.com/problems/swap-nodes-in-pairs/) 2 | 3 | > 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 4 | > 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 5 | 6 | > 示例: 7 | > 给定 1->2->3->4, 你应该返回 2->1->4->3.。 8 | 9 | 解题思路:迭代法,建立哨兵结点,每次遍历两个节点,交换位置,直到遍历至空节点。 10 | ```java 11 | /** 12 | * 建立一个哨兵节点 preHead 13 | * p1 指向当前节点,p2 指向下一节点,交换二者位置 14 | * 每次遍历链表两个节点,若遍历空节点则结束遍历 15 | */ 16 | class Solution { 17 | public ListNode swapPairs(ListNode head) { 18 | ListNode preHead = new ListNode(0); 19 | ListNode node = preHead; 20 | while (head != null && head.next != null) { 21 | ListNode next = head.next.next; // 存储下一要遍历节点 22 | // head.next=head; // 交换节点 23 | node.next=head.next; 24 | node.next.next=head; 25 | node=node.next.next; 26 | head=next; // 向后遍历两个节点 27 | } 28 | node.next=head; 29 | return preHead.next; 30 | } 31 | } 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /LeetCode25. K 个一组翻转链表.md: -------------------------------------------------------------------------------- 1 | # K 个一组翻转链表 [题目链接](https://leetcode-cn.com/problems/reverse-nodes-in-k-group/) 2 | 3 | > 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 4 | > k 是一个正整数,它的值小于或等于链表的长度。 5 | > 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 6 | 7 | > 示例 : 8 | > 给定这个链表:1->2->3->4->5 9 | > 当 k = 2 时,应当返回: 2->1->4->3->5 10 | > 当 k = 3 时,应当返回: 3->2->1->4->5 11 | 12 | 思路: 13 | 14 | 1. 在建立哨兵节点(牺牲一个头结点),迭代法的思路基础上修改代码 15 | 2. 建立一个链式栈,用 prev 指针做串联 16 | 3. 每次遍历 K 个节点,若遍历到空节点则结束遍历,prev 指向栈尾节点 17 | 4. 若未遍历空节点,则 prev 指针按照出栈顺序依次串联节点 18 | 19 | ```java 20 | public ListNode reverseKGroup(ListNode head, int k) { 21 | ListNode preHead = new ListNode(0); 22 | ListNode prev=preHead; 23 | LinkedList stack = new LinkedList<>(); 24 | while (head != null) { 25 | while (head!=null&&stack.size() < k) { 26 | stack.push(head); // 入栈 27 | head = head.next; 28 | } 29 | if (stack.size() == k) { 30 | while (head != null && stack.size() > 0) { 31 | prev.next = stack.poll(); 32 | prev = prev.next; 33 | } 34 | } else { 35 | prev.next=stack.pollLast(); 36 | return preHead.next; 37 | } 38 | } 39 | prev.next = head; 40 | return preHead.next; 41 | } 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /LeetCode27. 移除元素.md: -------------------------------------------------------------------------------- 1 | # 移除元素 [题目链接](https://leetcode-cn.com/problems/remove-element/submissions/) 2 | 3 | > 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 4 | > 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 5 | 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 6 | 7 | > 示例 1: 8 | > 给定 nums = [3,2,2,3], val = 3, 9 | > 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 10 | > 来源:力扣(LeetCode) 11 | 12 | 思路:遍历数组,若找到与 val 不同值,放置在对应索引,否则跳过 13 | ```java 14 | class Solution { 15 | public int removeElement(int[] nums, int val) { 16 | int len = nums.length; 17 | if (nums == null || len <= 0) { 18 | return 0; 19 | } 20 | int count = 0; // 统计不重复数 21 | for (int i = 0; i < len; i++) { 22 | if (nums[i] != val) { 23 | nums[count] = nums[i]; 24 | count++; 25 | } 26 | } 27 | // System.out.println(Arrays.toString(nums)); 28 | return count; 29 | } 30 | } 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /LeetCode28. 实现strStr().md: -------------------------------------------------------------------------------- 1 | # 实现strStr() [题目链接](https://leetcode-cn.com/problems/implement-strstr/) 2 | 实现 strStr() 函数。 3 | 4 | > 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 5 | > (从0开始)。如果不存在,则返回 -1。 6 | 7 | > 示例 1: 8 | > 输入: haystack = "hello", needle = "ll" 输出: 2 9 | > 来源:力扣(LeetCode) 10 | 11 | BF 暴力法思路: 12 | 13 | 1. 在主串 haystack 中找到与,模式串 needle 相匹配的第一个字符 14 | 2. 再比较后序字符是否相等,然后再在后序的字符中继续匹配 15 | 3. 若完全一致则返回主串匹配首字符索引,若不匹配则继续寻找匹配子串 16 | 17 | ```java 18 | class Solution { 19 | public int strStr(String haystack, String needle) { 20 | if (needle == null || "".equals(needle)) { 21 | return 0; 22 | } 23 | int len1 = haystack.length(); 24 | int len2 = needle.length(); 25 | for (int i = 0; i <= len1 - len2; i++) { 26 | if (haystack.charAt(i) == needle.charAt(0)&&haystack.substring(i,i+len2).equals(needle)) { 27 | return i; 28 | } 29 | } 30 | return -1; // 默认返回 -1 31 | } 32 | } 33 | ``` 34 | RK 算法在 BF 算法的基础上优化匹配的方式,建立哈希表,若计算出的哈希值一致,则认为二者为同一字符。 35 | ```java 36 | class Solution { 37 | public int strStr(String haystack, String needle) { 38 | if (needle == null || "".equals(needle)) { 39 | return 0; 40 | } 41 | Map map = new HashMap<>(); 42 | map.put(needle, 1); 43 | int len1 = haystack.length(); 44 | int len2 = needle.length(); 45 | for (int i = 0; i <= len1 - len2; i++) { 46 | if (haystack.charAt(i) == needle.charAt(0)&&map.get(haystack.substring(i,i+len2))!=null) { 47 | return i; 48 | } 49 | } 50 | return -1; 51 | } 52 | } 53 | ``` 54 | BM、KMP 有点复杂,后面理解清楚了再写对应解法。 55 | -------------------------------------------------------------------------------- /LeetCode29. 两数相除.md: -------------------------------------------------------------------------------- 1 | # 两数相除 [题目链接](https://leetcode-cn.com/problems/divide-two-integers/) 2 | 3 | > 给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。 4 | > 返回被除数 dividend 除以除数 divisor 得到的商。 5 | 6 | > 示例 1: 7 | > 输入: dividend = 10, divisor = 3 输出: 3 8 | > 来源:力扣(LeetCode) 9 | 10 | 思路:递归法,将除法转换为减法,递归处理相同操作 11 | 12 | 1. 除数与被除数都初始化为正数,商初始值为 1 13 | 2. 当除数减去被除数 > 被除数时,除数减去被除数,除数翻倍,count 翻倍 14 | 3. 当除数减去被除数 < 被除数时,被除数缩减一半,cout 减半 15 | 4. 当除数小于等于 0 ,或 count 为 0 时,则返回结果 16 | 17 | ```java 18 | public int divide(int dividend, int divisor) { 19 | if (dividend==Integer.MIN_VALUE && divisor==-1) { 20 | return Integer.MAX_VALUE; 21 | } 22 | long x = dividend < 0 ? -(long) dividend : (long) dividend; // 将除数与被除数转换为正数 23 | long y = divisor < 0 ? -(long) divisor : (long) divisor; 24 | int count = recurse(x, y, 1); 25 | return ((dividend >= 0 && divisor >= 0) || (dividend < 0 && (divisor < 0))) ? count : -count; // 同号则返回递归结果,异号返回相反结果 26 | } 27 | 28 | private int recurse(Long x,Long y,int count){ 29 | if (x <= 0 || count == 0) { 30 | return 0; // 除数除完,或无法除下被除数 31 | } 32 | if (x < y) { 33 | return recurse(x, y >>> 1, count >>> 1); 34 | } 35 | return recurse(x - y, y + y, count + count)+count; 36 | } 37 | 38 | public static void main(String[] args) { 39 | LeetCode29 lc = new LeetCode29(); 40 | System.out.println(lc.divide(Integer.MIN_VALUE,-1)); 41 | } 42 | ``` 43 | 44 | 参考:[英文社区解答](https://leetcode.com/problems/divide-two-integers/discuss/13512/Recursive-Java-Solution-2ms) 45 | 46 | -------------------------------------------------------------------------------- /LeetCode3. 无重复字符的最长子串.md: -------------------------------------------------------------------------------- 1 | # 无重复字符的最长子串 2 | >给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 3 | 4 | >示例 1: 5 | >输入: "abcabcbb" 6 | >输出: 3 7 | >解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 8 | 9 | 解题思路:这道题实际考察的是字符串匹配,我们可以滑动窗口的思路来解决这个问题。建立一个动态的窗口(实际就是无重复的子串)遍历主串,每遍历一个新字符则在窗口中查找是否包含该字符,无则窗口增大,继续遍历。若已存在该字符则记录窗口长度,将窗口滑动至重复字符后,继续向下遍历,最后返回窗口的最大长度。 10 | ```java 11 | public int lengthOfLongestSubstring(String s) { 12 | if(s.isEmpty()) return 0; 13 | int LongLen = 1; // 初始化最长子串长度为 1 14 | int length=s.length(); 15 | String subStr = s.substring(0,1); 16 | String temp=""; 17 | for(int i=1;iLongLen) 23 | LongLen = subStr.length(); 24 | subStr=subStr.substring(subStr.indexOf(temp)+1)+temp; // 从重复字符后开始组建新的无重复子串 25 | } 26 | else{ 27 | subStr+=temp; 28 | } 29 | } 30 | if(subStr.length()>LongLen) // 考虑特殊情况 31 | LongLen = subStr.length(); 32 | return LongLen; 33 | } 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /LeetCode316去除重复字母.md: -------------------------------------------------------------------------------- 1 | # LeetCode316去除重复字母 2 | 3 | #### [316. 去除重复字母](https://leetcode-cn.com/problems/remove-duplicate-letters/) 4 | 5 | 解题思路: 6 | 7 | 1、count[26] 记录每个字符出现次数,visited[26] 记录每个字母是否出现,遍历 s 字符,StringBuilder result 记录结果字符串 8 | 2、依序遍历 s 字符,若当前遍历字符,大于 result 末尾字符,且 result 末尾字符出现次数不为 0 则移除末尾字符, result 末尾字符出现次数 -1,直到 result 末尾字符小于当前遍历字符 or result 末尾字符出现次数为 0 9 | 3、比较结束 result 加入当前遍历字符 10 | 11 | ```java 12 | class Solution { 13 | public String removeDuplicateLetters(String s) { 14 | boolean[] visited = new boolean[26]; 15 | int[] count = new int[26]; 16 | StringBuilder result = new StringBuilder(); 17 | for (char c : s.toCharArray()) { 18 | count[c - 'a']++; 19 | } 20 | for (char c : s.toCharArray()) { 21 | if (!visited[c - 'a']) { 22 | while (result.length() > 0 && result.charAt(result.length() - 1) > c 23 | && count[result.charAt(result.length() - 1) - 'a'] > 0) { 24 | visited[result.charAt(result.length() - 1) - 'a'] = false; 25 | result.deleteCharAt(result.length() - 1); 26 | } 27 | visited[c - 'a'] = true; 28 | result.append(c); 29 | } 30 | count[c - 'a']--; 31 | } 32 | return result.toString(); 33 | } 34 | } 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /LeetCode32. 最长有效括号.md: -------------------------------------------------------------------------------- 1 | # 32. 最长有效括号 2 | 3 | > 给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 4 | 5 | > 示例 1: 6 | > 输入: "(()" 输出: 2 解释: 最长有效括号子串为 "()" 7 | > 来源:力扣(LeetCode) 8 | > 链接:https://leetcode-cn.com/problems/longest-valid-parentheses 9 | 10 | 解题思路: 11 | 12 | 1. 找到括号匹配的条件: 左右括号数相等 13 | 2. left、right、max 分别记录左括号数、右括号数、最大括号对数 14 | 3. 第一遍正序遍历,分别记录左右括号数,当「右括号数大于左括号数」,则配对不成立,重新计数。当「左右括号数相等」,则匹配成立,max 记录最大括号对数。 15 | 4. 解决:一次遍历结束左括号数大于右括号数,未记录最大括号数问题。 16 | 5. 逆序遍历字符串,不成立匹配条件「左括号数大于右括号数」,继续记录匹配括号数。 17 | 6. 返回最大括号对数 max*2 18 | ```java 19 | class Solution { 20 | public int longestValidParentheses(String s) { 21 | int left=0; // 左括号数 22 | int right = 0; // 右括号数 23 | int max=0; // 匹配括号对数 24 | int len = s.length(); // 字符串长度 25 | for (int i = 0; i < len; i++) { 26 | if (s.charAt(i)=='('){ 27 | left++; 28 | }else { 29 | right++; 30 | } 31 | if (right > left) { // 不满足配对则置零 32 | right = 0; 33 | left = 0; 34 | } else if (right == left) { // 满足匹配记录括号数 35 | max = max > left ? max : left; 36 | } 37 | } 38 | // 置零 39 | right=0; 40 | left = 0; 41 | for (int i = len-1; i >= 0; i--) { 42 | if (s.charAt(i)=='('){ 43 | left++; 44 | }else { 45 | right++; 46 | } 47 | if (right < left) { // 不满足配对则置零 48 | right = 0; 49 | left = 0; 50 | } else if (right == left) { // 满足匹配记录括号数 51 | max = max > left ? max : left; 52 | } 53 | } 54 | 55 | return max*2; 56 | } 57 | } 58 | ``` 59 | 逆序遍历,解决一次遍历结束左括号数大于右括号数,未记录最大括号数问题。参考了[官方题解的思路](https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode/)。 60 | -------------------------------------------------------------------------------- /LeetCode322. 零钱兑换.md: -------------------------------------------------------------------------------- 1 | # 零钱兑换 2 | >给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 3 | 4 | >示例 1: 5 | 输入: coins = [1, 2, 5], amount = 11 6 | 输出: 3 7 | 解释: 11 = 5 + 5 + 1 8 | 9 | >来源:力扣(LeetCode) 10 | 链接:https://leetcode-cn.com/problems/coin-change 11 | 12 | 思路分析:推导, min[amount]=min(min[amount-coins1]..min[amount-coinsN]) 13 | 14 | ```java 15 | class Solution { 16 | public int coinChange(int[] coins, int amount) { 17 | if (coins == null || coins.length < 1) { // 处理空指针异常 18 | return -1; 19 | } 20 | long[] min = new long[amount + 1]; // 存储最小硬币数,long 处理溢出 21 | Arrays.fill(min, Integer.MAX_VALUE); // 初始化 22 | min[0] = 0; 23 | for (int i = 1; i <= amount; i++) { 24 | for (int j = 0; j < coins.length; j++) { 25 | if (i >= coins[j]) { 26 | min[i] = min[i] > min[i - coins[j]] + 1 ? min[i - coins[j]] + 1 : min[i]; 27 | } 28 | } 29 | } 30 | return (int)(min[amount] == Integer.MAX_VALUE ? -1 : min[amount]); 31 | } 32 | } 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /LeetCode330. 按要求补齐数组.md: -------------------------------------------------------------------------------- 1 | # LeetCode330. 按要求补齐数组 2 | 3 | #### [330. 按要求补齐数组](https://leetcode-cn.com/problems/patching-array/) 4 | 5 | 思路参考:[ 官方题解 ](https://leetcode-cn.com/problems/patching-array/solution/an-yao-qiu-bu-qi-shu-zu-by-leetcode-solu-klp1/) 6 | 7 | 思路分析:贪心算法 8 | 9 | 定理:[1,x-1] 能表示的值范围为 [1,2x-1] 10 | 11 | 1、x表示 nums 当前能表示数最大值 12 | 13 | 2、依序遍历 nums,当 ```index < len && nums[index] <= x``` 说明 x 能正常满足,更新 x,判断nums 下一遍历数是否满足 14 | 15 | 3、不满足条件,则需要在 nums 添加一个 x,x 值更新 16 | 17 | ```java 18 | public int minPatches(int[] nums, int n) { 19 | int patch = 0; 20 | long x = 1; 21 | int index = 0, len = nums.length; 22 | while (x <= n) { 23 | if (index < len && nums[index] <= x) { 24 | x += nums[index]; 25 | index++; 26 | } else { 27 | patch++; 28 | x *= 2; 29 | } 30 | } 31 | return patch; 32 | } 33 | ``` -------------------------------------------------------------------------------- /LeetCode338. 比特位计数.md: -------------------------------------------------------------------------------- 1 | # 比特位计数 2 | >给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 3 | 4 | >示例 1: 5 | 输入: 2 6 | 输出: [0,1,1] 7 | 8 | >来源:力扣(LeetCode) 9 | 链接:https://leetcode-cn.com/problems/counting-bits 10 | 11 | 思路分析: 12 | 1. 方法 1,对于 0~num 中的每个数计算二进制位 1 的个数,可参考 191 题 13 | 2. 方法 2,寻找规律,5 的二进制位 个数为 4 的二进制位个数 +1, 2 的 二进制位为 0 的二进制位 +1, 14 | 3. 归纳 count[i]=count[i&(i-1)]+1,即,当前数二进制位 1 个数 = 最低位 1 消除后的数的二进制 1 个数 +1 15 | 16 | 方法 2 ,参考代码 17 | ```java 18 | class Solution { 19 | public int[] countBits(int num) { 20 | if (num < 0) { // 避免数组越界异常 21 | return null; 22 | } 23 | int[] count = new int[num + 1]; 24 | count[0] = 0; // 初始化 0 的二进位个数 25 | for (int i = 1; i <= num; i++) { 26 | // 当前数二进制位 1 个数 = 最低位 1 消除后的数的二进制 1 个数 +1 27 | count[i] = count[i & (i - 1)] + 1; 28 | } 29 | return count; 30 | } 31 | } 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /LeetCode345. 反转字符串中的元音字母.md: -------------------------------------------------------------------------------- 1 | # 反转字符串中的元音字母 [题目链接](https://leetcode-cn.com/problems/reverse-vowels-of-a-string/) 2 | >编写一个函数,以字符串作为输入,反转该字符串中的元音字母。 3 | 4 | >示例 1: 5 | 输入: "hello" 6 | 输出: "holle" 7 | 8 | 思路分析:**双指针法**,left、right 指针遍历至元音字符时停止 9 | 10 | 两指针都遍历到元音字符时交换字符,继续遍历,指针相交结束遍历返回结果 11 | ```java 12 | class Solution { 13 | public String reverseVowels(String s) { 14 | if (s == null || s.length() < 2) { 15 | return s; 16 | } 17 | HashSet vowels = new HashSet<>( // 元音字符表 18 | Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U')); 19 | StringBuilder result = new StringBuilder(s); 20 | int left = 0, right = result.length() - 1; 21 | while (left < right) { 22 | char charLeft = result.charAt(left), 23 | charRight = result.charAt(right); 24 | if (!vowels.contains(charLeft)) { 25 | left++; 26 | } else if (!vowels.contains(charRight)) { 27 | right--; 28 | } else { 29 | result.setCharAt(left, charRight); 30 | result.setCharAt(right, charLeft); 31 | right--; 32 | left++; 33 | } 34 | } 35 | return result.toString(); 36 | } 37 | } 38 | ``` 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /LeetCode347. 前 K 个高频元素.md: -------------------------------------------------------------------------------- 1 | # 前 K 个高频元素 [题目链接](https://leetcode-cn.com/problems/top-k-frequent-elements/) 2 | >给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 3 | 4 | >示例 1: 5 | 输入: nums = [1,1,1,2,2,3], k = 2 6 | 输出: [1,2] 7 | 8 | 思路分析: 9 | 10 | 1、根据 nums 统计每个元素出现的次数,以 Integer 为 key 出现次数为 value 11 | 12 | 2、再根据次数进行桶排序,对排序后的数倒序遍历加入 result 结果集,当前 k 个数 遍历完成结束遍历,返回 result。 13 | ```java 14 | class Solution { 15 | public List topKFrequent(int[] nums, int k) { 16 | HashMap hashMap = new HashMap<>(); 17 | for (int num : nums) { // 统计出现次数 18 | if (hashMap.containsKey(num)) { 19 | hashMap.put(num, hashMap.get(num) + 1); 20 | } else { 21 | hashMap.put(num, 1); 22 | } 23 | } 24 | int bucketSize = 0; 25 | for (Integer key : hashMap.keySet()) { // 计算桶数量 26 | bucketSize = bucketSize > hashMap.get(key) ? bucketSize : hashMap.get(key); // 27 | } 28 | List[] lists = new List[bucketSize + 1]; 29 | for (int i = 1; i < lists.length; i++) { // 初始化桶集合 30 | lists[i] = new ArrayList<>(); 31 | } 32 | for (Integer key : hashMap.keySet()) { 33 | lists[hashMap.get(key)].add(key); // 将元素放入对应桶中 34 | } 35 | List result = new ArrayList<>(); 36 | // 找出前 k 高 的元素 37 | for (int index = bucketSize; index > 0; index--) { 38 | if (lists[index].size()!=0) { 39 | k -= lists[index].size(); 40 | result.addAll(lists[index]); 41 | if (k == 0) { 42 | break; 43 | } 44 | } else { 45 | continue; 46 | } 47 | } 48 | return result; 49 | } 50 | } 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /LeetCode35. 搜索插入位置.md: -------------------------------------------------------------------------------- 1 | # 搜索插入位置 2 | 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 3 | 4 | > 你可以假设数组中无重复元素。 5 | 6 | > 示例 1: 7 | > 输入: [1,3,5,6], 5 8 | > 输出: 2 9 | > 来源:力扣(LeetCode) 10 | > 链接:https://leetcode-cn.com/problems/search-insert-position 11 | 12 | 思路分析:对于此类在有序数组中查找对应数、坐标问题都可以使用「二分查找」解题。 13 | ```java 14 | class Solution { 15 | public int searchInsert(int[] nums, int target) { 16 | if (nums == null || nums.length < 1) { 17 | return 0; 18 | } 19 | int start = 0,end=nums.length-1,mid=(start+end)>>>1; // >>> 无符号右移,避免相加溢出 20 | while (start <= end) { 21 | if (nums[mid] == target) { // 相等直接在当前点插入 22 | return mid; 23 | } else if (nums[mid] > target) { // 大于中位数则在前半段寻找 24 | end = mid - 1; 25 | } else { // 小于中位数则在后半段寻找 26 | start = mid + 1; 27 | } 28 | mid=(start+end)>>>1; // mid 为中位数坐标 29 | } 30 | return start; // 小于 nums[0] 时,在起始点插入,大于 nums[len-1] 时,在 nums.length 插入 31 | } 32 | } 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /LeetCode38. 报数.md: -------------------------------------------------------------------------------- 1 | # 报数 2 | > 报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下: 3 | 4 | 1. 1 5 | 2. 11 6 | 3. 21 7 | 4. 1211 8 | 5. 111221 9 | 10 | > 1 被读作 "one 1" ("一个一") , 即 11。 11 | > 11 被读作 "two 1s" ("两个一"), 即 21。 12 | > 21 被读作"one 2", "one 1" ("一个二" , "一个一") , 即 1211。 13 | > 给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。 14 | 15 | > 注意:整数顺序将表示为一个字符串。 16 | > 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/count-and-say 17 | 18 | 注意理解题意:题目其实是报前一个数,即第二个人报第一个数:1一个 1,记 11,第三个人报第二个数:2个 1,记 21,以此类推。 19 | 20 | 解题思路:对此类,依据上一情况求解,存在重复操作题目,采用递归解题(同样能用递归也能用循环解决)。 21 | 22 | 递归结束条件,n == 1 23 | 操作:记录上一个数中每个数字出现的次数。 24 | 返回记录数据。 25 | ```java 26 | class Solution { 27 | public String countAndSay(int n) { 28 | if (n == 1) { 29 | return "1"; 30 | } 31 | StringBuilder before =new StringBuilder(countAndSay(n - 1)) ; // 递归调用 32 | // 根据字符出现的次数统计 33 | StringBuilder result = new StringBuilder(""); // 字符串频繁增加,使用 StringBuilder 减少内存消耗 34 | int count = 1; 35 | char target = before.charAt(0); 36 | for (int i = 1; i < before.length(); i++) { 37 | if (before.charAt(i) != target) { 38 | result .append(count +""+ target); 39 | target = before.charAt(i); 40 | count = 1; 41 | } else { 42 | count++; 43 | } 44 | } 45 | result .append(count +""+ target); 46 | return result.toString(); 47 | } 48 | } 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /LeetCode39. 组合总和.md: -------------------------------------------------------------------------------- 1 | # 组合总和 2 | 3 | > 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 4 | > 的组合。 5 | > candidates 中的数字可以无限制重复被选取。 6 | 7 | > 说明: 8 | > 所有数字(包括 target)都是正整数。 解集不能包含重复的组合。 9 | 10 | > 示例 1: 11 | > 输入: candidates = [2,3,6,7], target = 7, 12 | > 所求解集为: [ [7], [2,2,3] ] 13 | > 来源:力扣(LeetCode) 14 | > 链接:https://leetcode-cn.com/problems/combination-sum 15 | 16 | 思路分析 —— 回溯法: 17 | 1. 遍历数组 candidates,依序遍历 canidates 数字,将已遍历数字加入新集合 list 18 | 2. 若 list 集合数字相加之和与 target 值相等,将当前组合加入 lists,继续寻找下一可能组合 19 | 3. 剪枝条件:遍历完数组,list 集合元素超过目标值 20 | ```java 21 | class Solution { 22 | List> lists = new ArrayList<>(); 23 | public List> combinationSum(int[] candidates, int target) { 24 | List list = new ArrayList<>(); 25 | backtracking(candidates,0,target,list,0); 26 | return lists; 27 | } 28 | 29 | private void backtracking(int[] candidates, int nowIndex, int target, List list,int sum) { 30 | if (sum == target) { 31 | lists.add(new ArrayList<>(list)); // List 存储的是对象的引用,这里需要存储一个新的对象 32 | return ; 33 | } 34 | if (sum > target||candidates.length==nowIndex) { 35 | return ; 36 | } 37 | for (int i = nowIndex; i < candidates.length; i++) { 38 | if (sum+candidates[i]<=target){ 39 | list.add(candidates[i]); 40 | backtracking(candidates, i , target, list, sum + candidates[i]); // // 数组对象可重复使用,所以传递索引为当前索引 41 | list.remove(list.size() - 1); 42 | } 43 | } 44 | } 45 | } 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /LeetCode395. 至少有 K 个重复字符的最长子串.md: -------------------------------------------------------------------------------- 1 | # LeetCode395. 至少有 K 个重复字符的最长子串 2 | 3 | #### [395. 至少有 K 个重复字符的最长子串](https://leetcode-cn.com/problems/longest-substring-with-at-least-k-repeating-characters/) 4 | 5 | 解法一:分治法,查考官方 [题解](https://leetcode-cn.com/problems/longest-substring-with-at-least-k-repeating-characters/solution/zhi-shao-you-kge-zhong-fu-zi-fu-de-zui-c-o6ww/) 6 | 7 | 1、遍历统计 s 中每个字符出现的频率 8 | 9 | 2、以字符出现次数小于 k 的字符切分字符串,最长字串必定出现在其中,result 记录满足要求子串的最大长度 10 | 11 | 3、若所有字符出现次数均大于 K ,直接返回该字串长度 12 | 13 | ```java 14 | public int longestSubstring(String s, int k) { 15 | return dfs(s.toCharArray(), 0, s.length(), k); 16 | } 17 | 18 | private int dfs(char[] str, int left, int right, int k) { 19 | int[] count = new int[26]; 20 | // 遍历统计 s 中每个字符出现的频率 21 | for (int i = left; i < right; i++) { 22 | count[str[i] - 'a']++; 23 | } 24 | char split = 0; 25 | // 记录切分字符串 26 | for (int i = 0; i < count.length; i++) { 27 | if (count[i] > 0 && count[i] < k) { 28 | split = (char) (i + 'a'); 29 | } 30 | } 31 | // 所有字符出现次数均大于 K ,直接返回该字串长度 32 | if (split == 0) { 33 | return right - left; 34 | } 35 | int result = 0, l = left; 36 | while (l < right) { 37 | while (l < right && str[l] == split) { 38 | l++; 39 | } 40 | if (l >= right) { 41 | break; 42 | } 43 | int star = l; 44 | // 依次切分字符串 45 | while (l < right && str[l] != split) { 46 | l++; 47 | } 48 | int len = dfs(str, star, l, k); 49 | result = Math.max(result, len); 50 | } 51 | return result; 52 | } 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /LeetCode40. 组合总和 II.md: -------------------------------------------------------------------------------- 1 | # 组合总和 II 2 | 3 | > 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 4 | > candidates 中的每个数字在每个组合中只能使用一次。 5 | 6 | > 说明: 7 | > 所有数字(包括目标数)都是正整数。 解集不能包含重复的组合。 8 | 9 | > 示例 1: 10 | > 输入: candidates = [10,1,2,7,6,1,5], target = 8, 11 | > 所求解集为: 12 | > [ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ] 13 | > 来源:力扣(LeetCode) 14 | > 链接:https://leetcode-cn.com/problems/combination-sum-ii 15 | 16 | 思路分析 —— 回溯法: 17 | 18 | 1. 排序数组 candidates,相同组合数字顺序一致,方便忽略重复项 19 | 2. 遍历数组 candidates,依序遍历 canidates 数字,将已遍历数字加入新集合 list 20 | 3. 若 list 集合数字相加之和与 target 值相等,且在 lists 不存在相同解,将当前组合加入 lists,继续寻找下一可能组合 21 | 4. 剪枝条件:遍历完数组,list 集合元素超过目标值 22 | 23 | ```java 24 | class Solution { 25 | List> lists = new ArrayList<>(); 26 | public List> combinationSum2(int[] candidates, int target) { 27 | List list = new ArrayList<>(); 28 | Arrays.sort(candidates); // 使数组元素有序化 29 | backtracking(candidates,0,target,list,0); 30 | return lists; 31 | } 32 | 33 | private void backtracking(int[] candidates, int nowIndex, int target, List list,int sum) { 34 | if (sum == target&&!lists.contains(list)) { // 忽略重复答案 35 | lists.add(new ArrayList<>(list)); // List 存储的是对象的引用,这里需要存储一个新的对象 36 | return ; 37 | } 38 | if (sum > target||candidates.length==nowIndex) { // 剪枝 39 | return ; 40 | } 41 | for (int i = nowIndex; i < candidates.length; i++) { 42 | if (sum+candidates[i]<=target){ 43 | list.add(candidates[i]); 44 | backtracking(candidates, i+1 , target, list, sum + candidates[i]); // 数组对象不可重复使用,所以传递索引为当前索引+1 45 | list.remove(list.size() - 1); 46 | } 47 | } 48 | } 49 | } 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /LeetCode409. 最长回文串.md: -------------------------------------------------------------------------------- 1 | # 409. 最长回文串 [题目链接](https://leetcode-cn.com/problems/longest-palindrome/) 2 | 解题思路: 3 | 4 | 最长回文串为偶数字符总数+(存在奇数字符+1,不存在奇数字符+0) 5 | 6 | ```java 7 | public int longestPalindrome(String s) { 8 | if (s == null || s.length() < 1) { 9 | return 0; 10 | } 11 | int oddLen = 0, evenLen = 0; 12 | Map map = new HashMap<>(); 13 | // 统计字符出现次数 14 | for (char c : s.toCharArray()) { 15 | if (map.containsKey(c)) { 16 | map.put(c, map.get(c) + 1); 17 | } else { 18 | map.put(c, 1); 19 | } 20 | } 21 | // 遍历 map 更新 evenLen、oddLen 22 | for (Character key : map.keySet()) { 23 | evenLen += map.get(key) / 2 * 2; 24 | if (oddLen == 0 && map.get(key) % 2 == 1) { 25 | oddLen = 1; 26 | } 27 | } 28 | return oddLen + evenLen; 29 | } 30 | ``` 31 | 算法优化: 32 | 33 | 1、考虑字符的特殊性,使用 int[128] 替换 HashMap 34 | 35 | 2、仅用一个变量 len 存储回文字符最大长度 36 | 37 | ```java 38 | public int longestPalindrome(String s) { 39 | if (s == null || s.length() < 1) { 40 | return 0; 41 | } 42 | int len = 0; 43 | int[] countChars = new int[128]; 44 | // 统计字符出现次数 45 | for (char c : s.toCharArray()) { 46 | countChars[c - 'a']++; 47 | } 48 | // 遍历 map 更新 evenLen、oddLen 49 | for (int countChar : countChars) { 50 | len += countChar / 2 * 2; 51 | if ((countChar & 1) == 1 && (len & 1) == 0) { 52 | len++; 53 | } 54 | } 55 | return len; 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /LeetCode435. 无重叠区间.md: -------------------------------------------------------------------------------- 1 | # 无重叠区间 2 | >给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 3 | 4 | >注意: 5 | 可以认为区间的终点总是大于它的起点。 6 | 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。 7 | 8 | >示例 1: 9 | 输入: [ [1,2], [2,3], [3,4], [1,3] ] 10 | 输出: 1 11 | 解释: 移除 [1,3] 后,剩下的区间没有重叠。 12 | 13 | >来源:力扣(LeetCode) 14 | 链接:https://leetcode-cn.com/problems/non-overlapping-intervals 15 | 16 | 思路分析: 17 | 18 | 1、根据结束区间进行升序排序,每次选取最小的 end 为后续留出更大的存储空间 19 | 20 | 3、当 end > intervals[i][0] 说明空间重叠,count++ 21 | 22 | 2、不重叠则更新 end 值,遍历结束返回 count 23 | ```java 24 | public int eraseOverlapIntervals(int[][] intervals) { 25 | if (intervals.length < 1) { 26 | return 0; 27 | } 28 | Arrays.sort(intervals, ((o1, o2) ->o1[1] - o2[1])); 29 | int count = 0, end = intervals[0][1]; 30 | for (int i = 1; i < intervals.length; i++) { 31 | if (end > intervals[i][0]) { 32 | count++; 33 | continue; 34 | } 35 | end = intervals[i][1]; 36 | } 37 | return count; 38 | } 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /LeetCode45. 跳跃游戏 II.md: -------------------------------------------------------------------------------- 1 | # 跳跃游戏 II 2 | 3 | > 给定一个非负整数数组,你最初位于数组的第一个位置。 4 | > 数组中的每个元素代表你在该位置可以跳跃的最大长度。 5 | > 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 6 | 7 | > 示例: 8 | > 输入: [2,3,1,1,4] 9 | > 输出: 2 10 | > 解释: 跳到最后一个位置的最小跳跃数是 2。 11 | > 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 12 | > 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/jump-game-ii 13 | 14 | 思路分析:基于「贪心算法」,每次选择所能跳跃最远的点作为下一跳跃点 15 | 16 | 跳跃距离=当前坐标+所能跳跃最大值 17 | 18 | ```java 19 | public int jump(int[] nums) { 20 | int index = 0, count =0; // 记录当前索引以及跳跃次数 21 | while (index+nums[index] < nums.length-1) { // 若当前已在终点或下一次能够到达终点则结束跳跃 22 | int max = 1; // 默认下一跳跃点为最大点 23 | for (int i = 2; i <= nums[index]; i++) { 24 | if (nums[index + i]+ i>= nums[index+max]+max) { // 选取最大跳跃 25 | max = i; 26 | } 27 | } 28 | index+=max; // 跳跃 29 | count++; // 计数 30 | } 31 | return index==nums.length-1?count:count+1; // 若下一次跳跃才能达到终点,则次数+1 32 | } 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /LeetCode452. 用最少数量的箭引爆气球.md: -------------------------------------------------------------------------------- 1 | # 用最少数量的箭引爆气球 2 | >在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够了。开始坐标总是小于结束坐标。平面内最多存在104个气球。 3 | 4 | >一支弓箭可以沿着x轴从不同点完全垂直地射出。在坐标x处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。 5 | 6 | >Example: 7 | 输入: 8 | [[10,16], [2,8], [1,6], [7,12]] 9 | 输出: 10 | 2 11 | 12 | >解释: 13 | 对于该样例,我们可以在x = 6(射爆[2,8],[1,6]两个气球)和 x = 11(射爆另外两个气球)。 14 | 15 | >来源:力扣(LeetCode) 16 | 链接:https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons 17 | 18 | 思路分析:与 LeetCode435 题思路一致。 19 | 20 | 根据结束坐标的大小对数组进行升序排序,count 记录无法合并数组数量。 21 | ```java 22 | class Solution { 23 | public int findMinArrowShots(int[][] points) { 24 | if (points.length < 1) { 25 | return 0; 26 | } 27 | Arrays.sort(points, ((o1, o2) -> o1[1] - o2[1])); // 使用 lambda 表达式执行效率更低 28 | int count = 1, end = points[0][1]; 29 | for (int i = 1; i < points.length; i++) { 30 | if (points[i][0]<=end) { 31 | continue; 32 | } 33 | count++; 34 | end = points[i][1]; 35 | } 36 | return count; 37 | } 38 | } 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /LeetCode455. 分发饼干.md: -------------------------------------------------------------------------------- 1 | # 分发饼干 2 | >假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 3 | 4 | >注意: 5 | 你可以假设胃口值为正。 6 | 一个小朋友最多只能拥有一块饼干。 7 | 8 | >示例 1: 9 | 输入: [1,2,3], [1,1] 10 | 输出: 1 11 | 12 | >来源:力扣(LeetCode) 13 | 链接:https://leetcode-cn.com/problems/assign-cookies 14 | 15 | 思路分析: 16 | 17 | 1、对小朋友的胃口值、饼干大小进行排序,每次从饼干中选出能够满足 小朋友胃口的最小值 18 | 19 | 2、每满足 1 个小朋友 count++,继续匹配下一对 20 | 21 | 3、indexS 存储上一次饼干坐标,当饼干或者小朋友遍历结束时结束分配 22 | 23 | ```java 24 | public int findContentChildren(int[] g, int[] s) { 25 | int count = 0, indexG = 0, indexS = 0; 26 | Arrays.sort(g); 27 | Arrays.sort(s); 28 | while (indexG < g.length && indexS < s.length) { 29 | if (s[indexS] >= g[indexG]) { // 最小值匹配成功 30 | indexG++; 31 | indexS++; 32 | count++; 33 | } else { 34 | indexS++; 35 | } 36 | } 37 | return count; 38 | } 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /LeetCode50. Pow(x, n).md: -------------------------------------------------------------------------------- 1 | # 50. Pow(x, n) [题目链接](https://leetcode-cn.com/problems/powx-n/) 2 | 3 | > 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 4 | 5 | > 示例 1: 6 | > 输入: 2.00000, 10 7 | > 输出: 1024.00000 8 | 9 | 思路分析: 10 | 11 | - x^n= x^n/2 * x^n/2 —— n 为偶数时, x^n= x^(n-1)/2 * x^(n+1)/2 —— n为奇数时 12 | - 当 n 为 负数时,x^n= 1/(-x)^n 13 | - 当 x 为正数时,x^n= x^n/2 * x^n/2 14 | - x 为负数时,偶数次方为正数,奇数次方为负数 15 | 16 | ```java 17 | class Solution { 18 | public double myPow(double x, int n) { 19 | if (n == 0) { 20 | return 1.0; 21 | } 22 | if (x == 1||x==0) { 23 | return x; 24 | } 25 | if (n < 0) { 26 | if (n == Integer.MIN_VALUE) { // 过滤特殊情况,放置 -n 溢出 int 范围 27 | return 1.0 / (myPow(x, (-n) >>> 1) * myPow(x, (-n) >>> 1)); 28 | } 29 | return 1.0 / myPow(x, -n); 30 | } 31 | if (x < 0) { 32 | return n%2==0?myPow(-x, n):-myPow(-x,n); // x 为负数时,偶数次方为正数,奇数次方为负数 33 | } 34 | double temp = x,result=1; 35 | while (n > 0) { 36 | if ((n % 2) == 1) { // x^n= x^(n-1)/2 * x^(n+1)/2 —— n为奇数时 37 | result*=temp; 38 | } 39 | temp*=temp; 40 | n >>= 1; 41 | } 42 | return result; 43 | } 44 | } 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /LeetCode509. 斐波那契数.md: -------------------------------------------------------------------------------- 1 | # LeetCode509. 斐波那契数 2 | 3 | #### [509. 斐波那契数](https://leetcode-cn.com/problems/fibonacci-number/) 4 | 5 | 解法一:自底向上——动态规划 6 | 7 | 动态方程 f(n)=f(n-1)+f(n-2) 8 | 9 | ```java 10 | public int fib(int n) { 11 | if (n < 2) { 12 | return n; 13 | } 14 | int result = 0, n1 = 1, n2 = 0; 15 | for (int i = 2; i < n; i++) { 16 | result = n1 + n2; 17 | n2 = n1; 18 | n1 = result; 19 | } 20 | return result; 21 | } 22 | ``` 23 | 24 | 解法二:递归 25 | 26 | ```java 27 | public int fib(int n) { 28 | if (n < 2) { 29 | return n; 30 | } 31 | return fib(n-1)+fib(n-2); 32 | } 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /LeetCode52. N皇后 II.md: -------------------------------------------------------------------------------- 1 | # 52. N皇后 II 2 | >给定一个整数 n,返回 n 皇后不同的解决方案的数量。 3 | 4 | >示例: 5 | >输入: 4 6 | 输出: 2 7 | 解释: 4 皇后问题存在如下两个不同的解法。 8 | [ 9 | [".Q..", // 解法 1 10 | "...Q", 11 | "Q...", 12 | "..Q."], 13 | ["..Q.", // 解法 2 14 | "Q...", 15 | "...Q", 16 | ".Q.."] 17 | ] 18 | 19 | >来源:力扣(LeetCode) 20 | 链接:https://leetcode-cn.com/problems/n-queens-ii 21 | 22 | 解题思路:基于 51 题,将生成结果集简化为统计解数即可。 23 | ```java 24 | private int resultCount = 0; // 记录解数 25 | public int totalNQueens(int n) { 26 | int result[] = new int[n]; 27 | backtracking(result,0); 28 | return resultCount; 29 | } 30 | private void backtracking(int[] result,int n){ 31 | if (n == result.length) { 32 | resultCount++; // 更新计数 33 | return; 34 | } 35 | for (int i = 0; i < result.length; i++) { 36 | if (isValidation(result, n, i)) { 37 | result[n] = i; 38 | backtracking(result, n + 1); 39 | } 40 | } 41 | } 42 | // 验证,无同行/同列棋子 43 | // 对角线无棋子 44 | private boolean isValidation(int[] result, int row, int col) { 45 | for (int i = 0; i < row; i++) { // 第一行可以放任意位置 46 | int sub = row - i; // 行数差 47 | // 避免同列、对角线出现皇后 48 | if (result[i]==col||result[i]==col-sub||result[i]==col+sub) { 49 | return false; 50 | } 51 | } 52 | return true; 53 | } 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /LeetCode524. 通过删除字母匹配到字典里最长单词.md: -------------------------------------------------------------------------------- 1 | # 通过删除字母匹配到字典里最长单词 2 | >给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删除给定字符串的某些字符来得到。如果答案不止一个,返回长度最长且字典顺序最小的字符串。如果答案不存在,则返回空字符串。 3 | 4 | >示例 1: 5 | 输入: 6 | s = "abpcplea", d = ["ale","apple","monkey","plea"] 7 | 输出: 8 | "apple" 9 | 10 | >来源:力扣(LeetCode) 11 | 链接:https://leetcode-cn.com/problems/longest-word-in-dictionary-through-deleting。 12 | 13 | 思路分析: 14 | 15 | 1、基于字典序对 d 内字符串进行排序,len 记录匹配的字符串最大长度,word 记录匹配的最大字符串 16 | 17 | 2、每次取出 d 中的一个字符串 str 与 s 匹配,判断 str 是否为 s 子串。 18 | 19 | 3、若 str 遍历字符与 s 遍历字符相等则匹配下一字符,不相等,则遍历 s 下一字符 20 | 21 | 4、当 str 所有字符都能匹配则 len 记录最大长度,word 记录字符串,无法完全匹配则取 d 下一字符。 22 | ```java 23 | public String findLongestWord(String s, List d) { 24 | if (s == null || d == null || s.length() < 1 || d.size() < 1) { 25 | return ""; 26 | } 27 | Collections.sort(d, (s1, s2) -> s1.length() != s2.length() ? 28 | s1.length() - s2.length() : s1.compareTo(s2)); // 基于字典顺序排序 29 | int len=0; 30 | String word = ""; 31 | for (String str : d) { 32 | if (str.length()>s.length()||!isSubStr(s,str)){ // 不满足字串条件 33 | continue; 34 | } 35 | if (str.length() > len) { // 记录最长子串以及长度 36 | len = str.length(); 37 | word = str; 38 | } 39 | } 40 | return word; 41 | } 42 | 43 | private boolean isSubStr(String str, String subStr) { // 判断是否为子串 44 | int indexStr = 0, indexSub = 0; 45 | while (indexStr < str.length() && indexSub < subStr.length()) { 46 | if (str.charAt(indexStr) != subStr.charAt(indexSub)) { 47 | indexStr++; 48 | } else { 49 | indexSub++; 50 | indexStr++; 51 | } 52 | } 53 | return indexSub == subStr.length(); 54 | } 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /LeetCode53. 最大子序和.md: -------------------------------------------------------------------------------- 1 | # 最大子序和 2 | >给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 3 | 4 | >示例: 5 | 输入: [-2,1,-3,4,-1,2,1,-5,4], 6 | 输出: 6 7 | 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 8 | 9 | >来源:力扣(LeetCode) 10 | 链接:https://leetcode-cn.com/problems/maximum-subarray 11 | 12 | 思路分析: 13 | 14 | 由果溯因,数组第 n 个数的最大连续子串和有两个选择:加上前一个数的最大连续子串和 / 仅保留自己,取两个选择中的最大值。 15 | 16 | --> 状态方程:`max[n]=max(max[n]+nums[n],num[n])-->max[n]>=0?max[n]+nums[n]:nums[n];` 17 | ```java 18 | public int maxSubArray(int[] nums) { 19 | // 处理空指针异常 20 | if (nums == null || nums.length < 1) { 21 | return 0; 22 | } 23 | int sum = nums[0], max = nums[0]; 24 | // 根据状态方程 max[n]=max[n]>=0?max[n]+nums[n]:nums[n]; 计算最大连续子串和 25 | for (int i = 1; i < nums.length; i++) { 26 | sum = sum >= 0 ? sum += nums[i] : nums[i]; 27 | max = sum > max ? sum : max; 28 | } 29 | return max; 30 | } 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /LeetCode54. 螺旋矩阵.md: -------------------------------------------------------------------------------- 1 | # 螺旋矩阵 2 | >给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 3 | 4 | >示例 1: 5 | 输入: 6 | [ 7 | [ 1, 2, 3 ], 8 | [ 4, 5, 6 ], 9 | [ 7, 8, 9 ] 10 | ] 11 | 输出: [1,2,3,6,9,8,7,4,5] 12 | 13 | >来源:力扣(LeetCode) 14 | 链接:https://leetcode-cn.com/problems/spiral-matrix 15 | 16 | 思路分析: 17 | 1. 螺旋遍历的规律:按照 上第一行(从左到右)-> 右竖行(从上到下) -> 下第一行(从右到左)-> 左竖行(从下到上)遍历放入 list 18 | 2. 特殊情况处理,只有一行时,只添加该行每项元素即可 19 | 3. 只有一列时, 20 | 4. 只有两行/两列时,不需要遍历内圈 21 | ```java 22 | class Solution { 23 | public List spiralOrder(int[][] matrix) { 24 | if (matrix == null || matrix.length < 1) { 25 | return new ArrayList<>(); 26 | } 27 | List result = new ArrayList<>(); 28 | help(matrix, 0, matrix.length - 1, result, 0); 29 | return result; 30 | } 31 | 32 | private void help(int[][] matrix, int startRow, int endRow,List result,int n) { 33 | // 第一行(从左到右) 34 | for (int col = n; col < matrix[startRow].length-n; col++) { 35 | result.add(matrix[startRow][col]); 36 | } 37 | if (endRow - startRow < 1) { // 只有一行 38 | return; 39 | } 40 | // 右竖行(从上到下) 41 | for (int row = startRow+1; row <= endRow ; row++) { 42 | result.add(matrix[row][matrix[row].length - n-1]); 43 | } 44 | if (matrix[startRow].length - 2*n <= 1) { // 只有一列 45 | return; 46 | } 47 | // 下第一行(从右到左) 48 | for (int col = matrix[endRow].length - n-2; col >= n; col--) { 49 | result.add(matrix[endRow][col]); 50 | } 51 | // 左竖行(从下到上) 52 | for (int row = endRow-1; row >startRow ; row--) { 53 | result.add(matrix[row][n]); 54 | } 55 | if (endRow - startRow < 2||matrix[startRow].length - 2*n == 2) { // 只有两行/两列,不需要再遍历内圈 56 | return; 57 | } 58 | help(matrix, startRow + 1, endRow - 1, result, n + 1); // 遍历内圈 59 | } 60 | } 61 | ``` 62 | 63 | -------------------------------------------------------------------------------- /LeetCode542. 01 矩阵.md: -------------------------------------------------------------------------------- 1 | # 542. 01 矩阵 [题目链接](https://leetcode-cn.com/problems/01-matrix/) 2 | 解题思路:动态规划 3 | 4 | 当前坐标最小距离=上下左右最小距离+1 or 当前坐标为0 5 | 6 | ```java 7 | public int[][] updateMatrix(int[][] matrix) { 8 | int rowLen = matrix.length, colLen = matrix[0].length; 9 | int[][] result = new int[rowLen][colLen]; 10 | for (int row = 0; row < rowLen; row++) { 11 | for (int col = 0; col < colLen; col++) { 12 | result[row][col] = matrix[row][col] == 0 ? 0 : 10000; 13 | } 14 | } 15 | // 第一遍计算根据左、上取最小值 16 | for (int row = 0; row < rowLen; row++) { 17 | for (int col = 0; col < colLen; col++) { 18 | if (row > 0) { 19 | result[row][col] = Math.min(result[row][col], result[row - 1][col]+1); 20 | } 21 | if (col > 0) { 22 | result[row][col] = Math.min(result[row][col], result[row][col - 1] + 1); 23 | } 24 | } 25 | } 26 | // 第二遍计算根据右、下取最小值 27 | for (int row = rowLen - 1; row >= 0; row--) { 28 | for (int col = colLen - 1; col >= 0; col--) { 29 | if (row+1给定一个非负整数数组,你最初位于数组的第一个位置。 3 | 数组中的每个元素代表你在该位置可以跳跃的最大长度。 4 | 判断你是否能够到达最后一个位置。 5 | 6 | >示例 1: 7 | 输入: [2,3,1,1,4] 8 | 输出: true 9 | 解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。 10 | 11 | >来源:力扣(LeetCode) 12 | 链接:https://leetcode-cn.com/problems/jump-game 13 | 14 | 解法一:正推,依次遍历每个格子,记录当前所能跳跃最大索引值,当无法跳跃到当前格子时,返回 false 15 | 16 | ```java 17 | public boolean canJump(int[] nums) { 18 | if (nums == null || nums.length < 1) { 19 | return false; 20 | } 21 | int max=0; 22 | for (int i = 0; i < nums.length; i++) { 23 | if (i > max) { 24 | return false; 25 | } 26 | max = Math.max(max, i + nums[i]); 27 | } 28 | return true; 29 | } 30 | ``` 31 | 解法二:由果溯因,从终点向起点走,若能从终点走回起点,则说明可以跳跃,否,无法成功跳跃 32 | 33 | ```java 34 | public boolean canJump(int[] nums) { 35 | if (nums == null || nums.length < 1) { 36 | return false; 37 | } 38 | int target = nums.length - 1; 39 | for (int i = target; i >= 0; i--) { 40 | if (i + nums[i] >= target) { 41 | target = i; 42 | } 43 | } 44 | return target == 0; 45 | } 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /LeetCode56. 合并区间.md: -------------------------------------------------------------------------------- 1 | # 合并区间 2 | >给出一个区间的集合,请合并所有重叠的区间。 3 | 4 | >示例 1: 5 | 输入: [[1,3],[2,6],[8,10],[15,18]] 6 | 输出: [[1,6],[8,10],[15,18]] 7 | 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. 8 | 9 | >来源:力扣(LeetCode) 10 | 链接:https://leetcode-cn.com/problems/merge-intervals 11 | 12 | 思路分析: 13 | 1、将 intervals 数组放入 List 中根据 左区间大小对数组进行排序 14 | 15 | 2、当后一数组的左区间位于前一数组的右区间时进行合并,右区间为二者最大值 16 | 17 | 3、依次遍历 list 数组,每合并一个数组从 list 中删除被合并项,继续匹配下一数组,看是否能够合并 18 | ```java 19 | public int[][] merge(int[][] intervals) { 20 | if (intervals == null || intervals.length < 1) { 21 | return new int[0][]; 22 | } 23 | List lists = new ArrayList<>(); 24 | for (int i = 0; i < intervals.length; i++) { 25 | lists.add(intervals[i]); 26 | } 27 | Collections.sort(lists,(l1,l2)->l1[0]-l2[0]); 28 | int i = 1; 29 | while (i < lists.size()) { 30 | int start1=lists.get(i-1)[0],end1=lists.get(i-1)[1] 31 | ,start2=lists.get(i)[0],end2=lists.get(i)[1]; 32 | if (start2 >= start1 && start2 <= end1) { 33 | lists.get(i - 1)[1] = end1 > end2 ? end1 : end2; 34 | lists.remove(i); 35 | } else { 36 | i++; 37 | } 38 | } 39 | return lists.toArray(new int[0][]); 40 | } 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /LeetCode567. 字符串的排列.md: -------------------------------------------------------------------------------- 1 | # LeetCode567. 字符串的排列 2 | 3 | #### [567. 字符串的排列](https://leetcode-cn.com/problems/permutation-in-string/) 4 | 5 | 思路分析: 6 | 7 | 1、先判断 S2 窗口内是否满足:出现和 s1 同频次字符 8 | 9 | 2、不满足,更新窗口 10 | 11 | 3、满足,判断是否存在和 s1 长度一致且字符出现频率也一致的子字符串 12 | 13 | ```java 14 | public boolean checkInclusion(String s1, String s2) { 15 | char[] s1Chars = s1.toCharArray(); 16 | char[] s2Chars = s2.toCharArray(); 17 | int left = 0, right = 0, s1CharCount = 0, slideCharCount = 0; 18 | int[] s1CharFre = new int[26], slideCharFre = new int[26]; 19 | // 统计 s1 出现字符频率与不同字符数 20 | for (char c : s1Chars) { 21 | s1CharFre[c - 'a']++; 22 | } 23 | for (int i = 0; i < s1CharFre.length; i++) { 24 | s1CharCount = s1CharFre[i] > 0 ? s1CharCount + 1 : s1CharCount; 25 | } 26 | // 移动滑动窗口 27 | while (right < s2.length()) { 28 | if (s1CharFre[s2Chars[right] - 'a'] > 0) { 29 | slideCharFre[s2Chars[right] - 'a']++; 30 | if (slideCharFre[s2Chars[right] - 'a'] == s1CharFre[s2Chars[right] - 'a']) { 31 | slideCharCount++; 32 | } 33 | } 34 | right++; 35 | while (slideCharCount == s1CharCount) { 36 | if (right - left == s1.length()) { 37 | return true; 38 | } 39 | if (s1CharFre[s2Chars[left] - 'a'] > 0) { 40 | slideCharFre[s2Chars[left] - 'a']--; 41 | if (slideCharFre[s2Chars[left] - 'a'] < s1CharFre[s2Chars[left] - 'a']) { 42 | slideCharCount--; 43 | } 44 | } 45 | left++; 46 | } 47 | } 48 | return false; 49 | } 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /LeetCode57. 插入区间.md: -------------------------------------------------------------------------------- 1 | # 57. 插入区间 [题目链接](https://leetcode-cn.com/problems/insert-interval/) 2 | 解题思路: 3 | 4 | 1、依据题意可以将区间列表分为 3 个部分:小于 newInterval[0]、与 newInterval 重叠、大于 newInterval[1]. 5 | 6 | 2、对于 newInterval 非重叠区域,只需要保持原样即可,对于 newInterval 重叠区间,进行合并。 7 | 8 | ```java 9 | public int[][] insert(int[][] intervals, int[] newInterval) { 10 | // cur 代表当前操作 output 索引,index 代表当前操作 intervals 索引 11 | int newStart = newInterval[0], newEnd = newInterval[1], cur = 0, index = 0; 12 | // output 存储新的区间列表,最长不超过 intervals.length + 1 13 | int[][] output = new int[intervals.length + 1][2]; 14 | // 填补小于 newStart 的区域 15 | while (index < intervals.length && intervals[index][0] < newStart) { 16 | output[cur++] = intervals[index++]; 17 | } 18 | // 填补 newStart 所在区域 19 | if (cur == 0 || output[cur - 1][1] < newStart) { 20 | output[cur][0] = newStart; 21 | output[cur++][1] = newEnd; 22 | } else { 23 | output[cur-1][1] = Math.max(output[cur-1][1], newEnd); 24 | } 25 | // 填补大于 newEnd 区域 26 | while (index < intervals.length) { 27 | if (output[cur - 1][1] < intervals[index][0]) { 28 | output[cur++] = intervals[index++]; 29 | } else { 30 | output[cur - 1][1] = Math.max(intervals[index][1], output[cur - 1][1]); 31 | index++; 32 | } 33 | } 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /LeetCode58. 最后一个单词的长度.md: -------------------------------------------------------------------------------- 1 | # 最后一个单词的长度 2 | >给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度。 3 | 如果不存在最后一个单词,请返回 0 。 4 | 说明:一个单词是指由字母组成,但不包含任何空格的字符串。 5 | 6 | >示例: 7 | 输入: "Hello World" 8 | 输出: 5 9 | 10 | >来源:力扣(LeetCode) 11 | 链接:https://leetcode-cn.com/problems/length-of-last-word 12 | 13 | 思路分析:从后往前匹配,从第一个非空格字符开始匹配,每遍历一个非空格字符 count+1,在非空字符后出现空字符/遍历结束时,停止计数。 14 | 15 | ```java 16 | public int lengthOfLastWord(String s) { 17 | if (s == null || s.length() < 1) { 18 | return 0; 19 | } 20 | int count = 0; 21 | boolean flag = false; // 标记是否已匹配非空字符 22 | for (int i = s.length()-1; i >=0 ; i--) { 23 | if (s.charAt(i) != ' ') { 24 | flag = true; 25 | count++; 26 | flag = true; 27 | } else if (flag&& s.charAt(i) == ' ') { 28 | break; 29 | } 30 | } 31 | return count; 32 | } 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /LeetCode6. Z 字形变换.md: -------------------------------------------------------------------------------- 1 | # Z 字形变换 [题目链接](https://leetcode-cn.com/problems/zigzag-conversion/) 2 | >将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。 3 | >比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下: 4 | 5 | >L C I R 6 | >E T O E S I I G 7 | >E D H N 8 | 9 | >之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。 10 | >请你实现这个将字符串进行指定行数变换的函数: 11 | >string convert(string s, int numRows); 12 | 13 | >示例 1: 14 | >输入: s = "LEETCODEISHIRING", numRows = 3 15 | >输出: "LCIRETOESIIGEDHN" 16 | 17 | 思路分析: 18 | 19 | 1、Z 形排列可以可以由两部分组成,第一部分为竖排按顺序排列,第二部分为斜排从第二排开始倒序排列 20 | 21 | 2、由此可得 Z 字形的周期 2numRows-2 22 | 23 | 3、只要依序遍历字符串,将每一字符放入对应行,再将每行相加就是需要返回的 Z 形字符串。 24 | ```java 25 | public String convert(String s, int numRows) { 26 | // Z 字形的周期 2numRows-2 27 | if(s.isEmpty()||numRows<=1) return s; 28 | String[] row = new String[numRows+1]; // 存储每一行字符 29 | for(int i=0;i假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。 3 | 给定一个花坛(表示为一个数组包含0和1,其中0表示没种植花,1表示种植了花),和一个数 n 。能否在不打破种植规则的情况下种入 n 朵花?能则返回True,不能则返回False。 4 | 5 | >示例 1: 6 | 输入: flowerbed = [1,0,0,0,1], n = 1 7 | 输出: True 8 | 9 | >来源:力扣(LeetCode) 10 | 链接:https://leetcode-cn.com/problems/can-place-flowers 11 | 12 | 方法一,思路分析: 13 | 14 | 1、从 flowerbed 起始点(前一个元素不为0)开始种植花,n--,flag 标记当前是否已种花。 15 | 16 | 2、若下一位置为 0 ,则上一种植成立,在下一点尝试种植新的花。 17 | 18 | 3、若下一位置不为 0,则上一种植不合法,N++,flag=false。 19 | 20 | 若种结束遍历时 n<=0 则能够种植数量为 n 的花,等式不成立则不能 21 | 22 | ```java 23 | public boolean canPlaceFlowers(int[] flowerbed, int n) { 24 | boolean flag = false; // 标记当前是否种植花 25 | for (int i = 0; i < flowerbed.length && n >= 0; i++) { 26 | if (!flag && flowerbed[i] == 0) { 27 | if (i > 0 && flowerbed[i - 1] == 1) { 28 | continue; 29 | } 30 | flag = true; 31 | n--; 32 | } else if (flag) { 33 | flag = false; 34 | n = flowerbed[i] == 1 ? n + 1 : n; 35 | } 36 | } 37 | return n <= 0; 38 | } 39 | ``` 40 | 方法二,思路分析: 41 | 42 | 1、pre 记录前一元素值、next 记录下一元素值,针对首尾边界值进行特殊处理 43 | 44 | 2、当 pre、next 都为 0 时,则当前种植符合要求,n-- 45 | 46 | 3、不满足,则继续判断下一元素是否符合要求 47 | 48 | 4、当 n<=0 则能够种植数量为 n 的花 49 | 50 | ```java 51 | public boolean canPlaceFlowers(int[] flowerbed, int n) { 52 | for (int i = 0; i < flowerbed.length && n > 0; i++) { 53 | int pre = i == 0 ? 0 : flowerbed[i - 1], 54 | next = i == flowerbed.length - 1 ? 0 : flowerbed[i + 1]; 55 | if (pre == 0 && next == 0 && flowerbed[i] == 0) { // 满足种植条件,更新 n 和 flowerbed[i] 56 | n--; 57 | flowerbed[i] = 1; 58 | } 59 | } 60 | return n <= 0; 61 | } 62 | ``` 63 | 64 | -------------------------------------------------------------------------------- /LeetCode61. 旋转链表.md: -------------------------------------------------------------------------------- 1 | # LeetCode61. 旋转链表 2 | 3 | #### [61. 旋转链表](https://leetcode-cn.com/problems/rotate-list/) 4 | 5 | 思路分析: 6 | 7 | 1、首次遍历,计算出链表长度 len,k=k%len,index=len-k,tail 指向链表末尾节点 8 | 2、 将 [1,index] 节点移动至链表末尾,mid 代表 index 节点 9 | 3、newHead=mid.next,tail.next=head,mid.next=nul 10 | 11 | ```java 12 | public ListNode rotateRight(ListNode head, int k) { 13 | int len = 0; 14 | ListNode tail = head, node = head; 15 | while (node != null) { 16 | len++; 17 | tail = node; 18 | node = node.next; 19 | } 20 | k = len == 0 ? 0 : k % len; 21 | if (k == 0) { 22 | return head; 23 | } 24 | int index = len - k; 25 | node = head; 26 | for (int i = 1; i < index; i++) { 27 | node = node.next; 28 | } 29 | ListNode newNode = node.next; 30 | tail.next = head; 31 | node.next = null; 32 | return newNode; 33 | } 34 | ``` 35 | 36 | 代码优化基于 [官方题解:闭合为环](https://leetcode-cn.com/problems/rotate-list/solution/xuan-zhuan-lian-biao-by-leetcode-solutio-woq1/) 37 | 38 | 思路:首次遍历后 tail.next 指向 head,当 i=index 时,newNode = node.next,node.next=null 39 | 40 | ```java 41 | public ListNode rotateRight(ListNode head, int k) { 42 | int len = 0; 43 | ListNode tail = head, node = head; 44 | while (node != null) { 45 | len++; 46 | tail = node; 47 | node = node.next; 48 | } 49 | k = len == 0 ? 0 : k % len; 50 | if (k == 0) { 51 | return head; 52 | } 53 | int index = len - k; 54 | node = head; 55 | tail.next=head; 56 | for (int i = 1; i < index; i++) { 57 | node = node.next; 58 | } 59 | ListNode newNode = node.next; 60 | node.next = null; 61 | return newNode; 62 | } 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /LeetCode62. 不同路径.md: -------------------------------------------------------------------------------- 1 | # 不同路径 2 | >一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 3 | 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。 4 | 问总共有多少条不同的路径? 5 | 6 | >示例 1: 7 | 输入: m = 3, n = 2 8 | 输出: 3 9 | 解释: 10 | 从左上角开始,总共有 3 条路径可以到达右下角。 11 | >1. 向右 -> 向右 -> 向下 12 | >2. 向右 -> 向下 -> 向右 13 | >3. 向下 -> 向右 -> 向右 14 | 15 | >来源:力扣(LeetCode) 16 | 链接:https://leetcode-cn.com/problems/unique-paths 17 | 18 | 思路分析:动态规划,以空间换时间 19 | 1. 当前坐标路径数为左一格路径数 + 上一格路径数之和 20 | 2. 状态方程:sum[m,n]=sum[m-1][n]+sum[m][n-1]; 21 | 3. 初始化 sum[] 存储每个坐标的路径数:因为只能向下、向右移动 --> 第一行第一列的路径数都为 1 22 | ```java 23 | class Solution { 24 | public int uniquePaths(int m, int n) { 25 | if (m < 1 || n < 1) { 26 | return 0; 27 | } 28 | int[][] sum = new int[m][n]; // 存储坐标路径数 29 | // 初始化第一行,第一列路径数 30 | for (int row = 0; row < sum[0].length; row++) { 31 | sum[0][row] = 1; 32 | } 33 | for (int col = 1; col < sum.length; col++) { 34 | sum[col][0] = 1; 35 | } 36 | // 推导每个坐标的路径数 37 | for (int row = 1; row < sum.length; row++) { 38 | for (int col = 1; col < sum[row].length; col++) { 39 | sum[row][col] = sum[row - 1][col] + sum[row][col - 1]; 40 | } 41 | } 42 | return sum[m - 1][n - 1]; 43 | } 44 | } 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /LeetCode621. 任务调度器.md: -------------------------------------------------------------------------------- 1 | # LeetCode621. 任务调度器 2 | 3 | #### [621. 任务调度器](https://leetcode-cn.com/problems/task-scheduler/) 4 | 5 | 参考:[官方题解](https://leetcode-cn.com/problems/task-scheduler/solution/ren-wu-diao-du-qi-by-leetcode-solution-ur9w/) 6 | 7 | 思路分析: 8 | 9 | 1、任务的执行时间由出现次数最多的任务决定 = (出现次数最多的任务次数-1)* 等待时间+最多任务个数 -- (maxTask-1) *(n+1) + count(maxTask)* ,可以画图分析 10 | 11 | 2、特殊情况:非重复任务个数>冷却时间,此时冷却时间可省略,取任务总数 12 | 13 | ```java 14 | public int leastInterval(char[] tasks, int n) { 15 | Map countTask = new HashMap<>(16); 16 | int maxCount = 0; 17 | for (char task : tasks) { 18 | int count = countTask.getOrDefault(task, 0) + 1; 19 | maxCount = Math.max(count, maxCount); 20 | countTask.put(task, count); 21 | } 22 | int countMaxTask = 0; 23 | for (Map.Entry entry : countTask.entrySet()) { 24 | if (entry.getValue() == maxCount) { 25 | countMaxTask++; 26 | } 27 | } 28 | return Math.max(tasks.length, (maxCount - 1) * (n + 1) + countMaxTask); 29 | } 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /LeetCode628. 三个数的最大乘积.md: -------------------------------------------------------------------------------- 1 | # LeetCode628. 三个数的最大乘积 2 | 3 | #### [628. 三个数的最大乘积](https://leetcode-cn.com/problems/maximum-product-of-three-numbers/) 4 | 5 | 解题思路:本题主要考察代码的健壮性 6 | 7 | nums 元素的取值范围是 [-1000,1000],其三个数的最大乘积,我们要真的正负数的个数进行考虑。 8 | 9 | 1、无正数,取最大的三个数 10 | 11 | 2、1-2个正数,取最小两个负数*正数最大值 12 | 13 | 3、3 个及以上正数 Math(最小两数*最大数,最大三数乘积) 14 | 15 | 综合情况 max=Math.max(min1 * min2 * max1, max1 * max2 * max3) 16 | 17 | ```java 18 | public int maximumProduct(int[] nums) { 19 | // min1、min2 分别记录最小、第二小值 20 | int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE; 21 | // max1、max2、max3 分别记录第一大、第大二、第三大值 22 | int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE; 23 | // 遍历 nums 更新 5 个数 24 | for (int num : nums) { 25 | if (num < min1) { 26 | min2 = min1; 27 | min1 = num; 28 | } else if (num < min2) { 29 | min2 = num; 30 | } 31 | if (max1 < num) { 32 | max3 = max2; 33 | max2 = max1; 34 | max1 = num; 35 | } else if (max2 < num) { 36 | max3 = max2; 37 | max2 = num; 38 | } else if (max3 < num) { 39 | max3 = num; 40 | } 41 | } 42 | return Math.max(min1 * min2 * max1, max1 * max2 * max3); 43 | } 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /LeetCode63. 不同路径 II.md: -------------------------------------------------------------------------------- 1 | # 不同路径 II 2 | >一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 3 | 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 4 | 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径? 5 | 6 | >示例 1: 7 | 输入: 8 | [ 9 | [0,0,0], 10 | [0,1,0], 11 | [0,0,0] 12 | ] 13 | 输出: 2 14 | 解释: 15 | 3x3 网格的正中间有一个障碍物。 16 | 从左上角到右下角一共有 2 条不同的路径: 17 | 1. 向右 -> 向右 -> 向下 -> 向下 18 | 2. 向下 -> 向下 -> 向右 -> 向右 19 | 20 | >来源:力扣(LeetCode) 21 | 链接:https://leetcode-cn.com/problems/unique-paths-ii 22 | 23 | 思路分析: 24 | 1. 在 62 题的基础上多一步判断,若 obstacleGrid[m][n]=1 将当前位置的路径数置0 25 | 2. 当前坐标路径数为左一格路径数 + 上一格路径数之和 26 | 3. 状态方程:sum[m,n]=sum[m-1][n]+sum[m][n-1]; 27 | 4. 初始化 sum[] 存储每个坐标的路径数:因为只能向下、向右移动 --> 第一行第一列的路径数受上一初始化坐标影响,若当前坐标为障碍物则路径数为 0,否则与上一遍历坐标路径数一致 `sum[0][row] = sum[0][row-1];` / `sum[col][0] = sum[col - 1][0];` 28 | ```java 29 | class Solution { 30 | public int uniquePathsWithObstacles(int[][] obstacleGrid) { 31 | if (obstacleGrid == null || obstacleGrid.length < 1 || obstacleGrid[0][0] == 1) { 32 | return 0; 33 | } 34 | int rowLen = obstacleGrid.length, colLen = obstacleGrid[0].length; 35 | int[][] sum = new int[rowLen][colLen]; // 存储坐标路径数 36 | // 初始化第一行,第一列路径数 37 | sum[0][0] = 1; 38 | for (int row = 1; row < sum[0].length; row++) { 39 | sum[0][row] = obstacleGrid[0][row]==1 ? 0 : sum[0][row-1]; 40 | } 41 | for (int col = 1; col < sum.length; col++) { 42 | sum[col][0] = obstacleGrid[col][0] == 1 ? 0 : sum[col - 1][0]; 43 | } 44 | // 推导每个坐标的路径数 45 | for (int row = 1; row < sum.length; row++) { 46 | for (int col = 1; col < sum[row].length; col++) { 47 | sum[row][col] = obstacleGrid[row][col] == 1 ? 0 : 48 | sum[row - 1][col] + sum[row][col - 1]; 49 | } 50 | } 51 | return sum[rowLen - 1][colLen - 1]; 52 | } 53 | } 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /LeetCode633. 平方数之和.md: -------------------------------------------------------------------------------- 1 | # 平方数之和 2 | >给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c。 3 | 4 | >示例1: 5 | 输入: 5 6 | 输出: True 7 | 解释: 1 * 1 + 2 * 2 = 5 8 | 9 | >来源:力扣(LeetCode) 10 | 链接:https://leetcode-cn.com/problems/sum-of-square-numbers 11 | 12 | 解题思路:**双指针法**,从【0-sqrt ( c )】中找出评方和为 c,left 从左至右开始取数,right 从右至左开始取数。 13 | 14 | 若平方和大于 c,right--,小于 c left++,等于则返回 true,指针相交则返回 false。 15 | 16 | ```java 17 | class Solution { 18 | public boolean judgeSquareSum(int c) { 19 | int left = 0, right = (int) Math.sqrt(c); 20 | while (left <= right) { 21 | int sum = left * left + right * right; 22 | if (sum < c) { 23 | left++; 24 | } else if (sum > c) { 25 | right--; 26 | } else { 27 | return true; 28 | } 29 | } 30 | return false; 31 | } 32 | } 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /LeetCode64. 最小路径和.md: -------------------------------------------------------------------------------- 1 | # 最小路径和 2 | >给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 3 | 说明:每次只能向下或者向右移动一步。 4 | 5 | >示例: 6 | 输入: 7 | [ 8 | [1,3,1], 9 | [1,5,1], 10 | [4,2,1] 11 | ] 12 | 输出: 7 13 | 解释: 因为路径 1→3→1→1→1 的总和最小。 14 | 15 | >来源:力扣(LeetCode) 16 | 链接:https://leetcode-cn.com/problems/minimum-path-sum 17 | 18 | 思路分析:动态规划,推导状态方程 19 | 20 | 1. 当前坐标点有两个进入方法,上方结点向下走,左侧结点向右走,则当前路径最小值为 左 / 上 坐标点最小路径值。 21 | 2. 状态方程:min[m,n]=Min(min[m-1,n],min[m,n-1])+grid[m,n] 22 | 3. 初始化第一行第一列路径值:`min[0][i] = min[0][i-1] +grid[0][i];` `min[i][0] = min[i - 1][0] + grid[i][0];` 23 | ```java 24 | class Solution { 25 | public int minPathSum(int[][] grid) { 26 | if (grid == null || grid.length < 1) { 27 | return 0; 28 | } 29 | int rowLen = grid.length, colLen = grid[0].length; 30 | int[][] min = new int[rowLen][colLen]; // 存储路径最小值 31 | // 初始化 min 第一行第一列 32 | min[0][0] = grid[0][0]; 33 | for (int i = 1; i < colLen; i++) { 34 | min[0][i] = min[0][i-1] +grid[0][i]; 35 | } 36 | for (int i = 1; i < rowLen; i++) { 37 | min[i][0] = min[i - 1][0] + grid[i][0]; 38 | } 39 | // 推导路径最小值 40 | for (int row = 1; row < rowLen; row++) { 41 | for (int col = 1; col < colLen; col++) { 42 | min[row][col] = Math.min(min[row - 1][col], min[row][col - 1]) + 43 | grid[row][col]; 44 | } 45 | } 46 | return min[rowLen - 1][colLen - 1]; 47 | } 48 | } 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /LeetCode643. 子数组最大平均数 I.md: -------------------------------------------------------------------------------- 1 | # LeetCode643. 子数组最大平均数 I 2 | 3 | #### [643. 子数组最大平均数 I](https://leetcode-cn.com/problems/maximum-average-subarray-i/) 4 | 5 | 解题思路:滑动窗口 6 | 7 | 1. sum记录当前滑动窗口元素和,max 记录滑动窗口元素和最大值 8 | 2. 每次更新滑动窗口移出左边界元素,加入右边界元素 9 | 3. 遍历结束 返回 max*1.0/k 10 | 11 | ```java 12 | public double findMaxAverage(int[] nums, int k) { 13 | int max = Integer.MIN_VALUE, sum = 0; 14 | for (int i = 0; i < nums.length; i++) { 15 | // 记录当前滑动窗口元素和 16 | sum += nums[i]; 17 | // 滑动窗口初始化 18 | if (i < k - 1) { 19 | continue; 20 | } 21 | // 更新最大值 22 | max = Math.max(sum, max); 23 | // 移出左边界元素 24 | sum -= nums[i - k + 1]; 25 | } 26 | return max * 1.0 / k; 27 | } 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /LeetCode674. 最长连续递增序列.md: -------------------------------------------------------------------------------- 1 | # LeetCode674. 最长连续递增序列 2 | 3 | #### [674. 最长连续递增序列](https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/) 4 | 5 | 解题思路:记录每次递增序列的长度,max存储最大长度 6 | 7 | ```java 8 | public int findLengthOfLCIS(int[] nums) { 9 | int max = 1, left = 0; 10 | for (int right = 1; right < nums.length; right++) { 11 | // 递增序列更新最大长度 12 | if (nums[right] > nums[right - 1]) { 13 | max = Math.max(right - left + 1, max); 14 | } else { // 非递增更新边界 15 | left = right; 16 | } 17 | } 18 | return nums.length == 0 ? 0 : max; // 处理特殊值 19 | } 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /LeetCode69. x 的平方根.md: -------------------------------------------------------------------------------- 1 | # x 的平方根 2 | >实现 int sqrt(int x) 函数。 3 | 计算并返回 x 的平方根,其中 x 是非负整数。 4 | 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 5 | 6 | > 示例 1: 7 | > 输入: 4 8 | > 输出: 2 9 | 10 | >来源:力扣(LeetCode) 11 | 链接:https://leetcode-cn.com/problems/sqrtx 12 | 13 | 思路分析: 14 | 1. 基于二分查找法,每次取中值判断其平方是否等于 x 15 | 2. 若小于则在左半边查找,大于则在右边查找,左右边界相等则返回最接近平方数的最小值 16 | ```java 17 | class Solution { 18 | public int mySqrt(int x) { 19 | if (x < 2) { // 处理特殊值 20 | return x; 21 | } 22 | int left = 0, right = x; 23 | while (left < right) { 24 | int mid = (left + right) >>> 1; // 取中值 25 | if (x/mid == mid) { // 找到平方根 26 | return mid; 27 | } else if (x / mid > mid) { // 大于则在右边查找 28 | left = mid + 1; 29 | } else { // 小于则在左半边查找 30 | right = mid - 1; 31 | } 32 | } 33 | return x / left < left ? left - 1 : left; // 取最小值 34 | } 35 | } 36 | ``` 37 | 38 | 方法 2 ,基于牛顿迭代法公式: 39 | ![牛顿跌代法公式](https://img-blog.csdnimg.cn/20190904105322345.png) 40 | 41 | ```java 42 | class Solution { 43 | public int mySqrt(int x) { 44 | if (x < 2) { 45 | return x; 46 | } 47 | int result = x; 48 | while (x / result < result) { // 不断迭代,逼近解 49 | result = (result + x / result) >>> 1; // 迭代公式 50 | } 51 | return result; 52 | } 53 | } 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /LeetCode697. 数组的度.md: -------------------------------------------------------------------------------- 1 | # LeetCode697. 数组的度 2 | 3 | #### [697. 数组的度](https://leetcode-cn.com/problems/degree-of-an-array/) 4 | 5 | 解题思路: 6 | 7 | 1. 首次遍历找到数组的度,同时记录每个数字出现的数字、首索引、结束索引 8 | 9 | 2. 遍历哈希表,更新与 nums 相同度的数字长度最小值 10 | 11 | ```java 12 | public int findShortestSubArray(int[] nums) { 13 | Map map = new HashMap<>(); 14 | int maxDegree = 0; 15 | for (int index = 0; index < nums.length; index++) { 16 | int[] degree = map.getOrDefault(nums[index], new int[]{0, index, index}); 17 | degree[0]++; 18 | degree[2] = index; 19 | maxDegree = Math.max(maxDegree, degree[0]); 20 | map.put(nums[index], degree); 21 | } 22 | int result = nums.length; 23 | for (Map.Entry entry : map.entrySet()) { 24 | int[] degree = entry.getValue(); 25 | if (degree[0] == maxDegree) { 26 | result = Math.min(result, degree[2] - degree[1] + 1); 27 | } 28 | } 29 | return result; 30 | } 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /LeetCode7. 整数反转.md: -------------------------------------------------------------------------------- 1 | # 整数反转 [题目链接](https://leetcode-cn.com/problems/reverse-integer/submissions/) 2 | >给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 3 | 4 | >示例 1: 5 | >输入: 123 6 | >输出: 321 7 | 8 | 第一种解法思路分析: 9 | 按照字符串反转的思路,len 为数组位数(strX 长度),第 i 位和 len-i-1 位交换位置即可。 10 | 对于 int 数字转换后可能出现的上溢出、下溢出进行特殊处理,直接返回 0. 11 | ```java 12 | public int reverse(int x) { 13 | if(x<=Integer.MIN_VALUE){ // 处理最下溢出 14 | return 0; 15 | } 16 | if(x<0){ 17 | return -reverse(-x); 18 | } 19 | char[] strX=String.valueOf(x).toCharArray(); 20 | int len = strX.length; 21 | char temp=' '; 22 | for(int i=0;i>1;i++){ // 反转 23 | temp=strX[i]; 24 | strX[i]=strX[len-i-1]; 25 | strX[len-i-1]=temp; 26 | } 27 | double returnNum =Double.parseDouble(String.copyValueOf(strX)); 28 | return returnNum>Integer.MAX_VALUE?0:(int)returnNum; // 处理上溢出 29 | } 30 | ``` 31 | 32 | 第二种解法,来自于官方解答 33 | 解题思路:把反转看做,低位向高位推进的过程。 34 | 从 x 的最低位开始处理,每次将 reN ( 返回数 ) 推进一位,取 x 最低位放置 reN的末尾。 35 | 当处理到需要 31 位来表示的整数时,判断个位是否大于 Int 最大最小值个位,做特殊处理。 36 | 37 | 补充:Java Int 可表示最大值: 2147483647、最小值:-2147483648。 38 | ```java 39 | public int reverse(int x) { 40 | int reN = 0; // 返回数 41 | int reminder = 0; // 余数 42 | while (x != 0) { 43 | reminder = x % 10; 44 | x /= 10; 45 | if (reN > Integer.MAX_VALUE / 10 || (reN == Integer.MAX_VALUE / 10 && reminder > 7)) { // int最大值个位为 7,超过 7 46 | return 0; 47 | } // 则上溢出 48 | if (reN < Integer.MIN_VALUE / 10 || (reN == Integer.MIN_VALUE / 10 && reminder > 8)) { 49 | return 0; // Int 最小值个位为 8 此时余数大于 8 则下溢出 50 | } 51 | reN = reN*10 + reminder; 52 | } 53 | return reN; 54 | } 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /LeetCode70. 爬楼梯.md: -------------------------------------------------------------------------------- 1 | # 70. 爬楼梯 2 | >假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 3 | 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 4 | 注意:给定 n 是一个正整数。 5 | 6 | >示例 1: 7 | 输入: 2 8 | 输出: 2 9 | 解释: 有两种方法可以爬到楼顶。 10 | >1. 1 阶 + 1 阶 11 | >2. 2 阶 12 | 13 | >来源:力扣(LeetCode) 14 | 链接:https://leetcode-cn.com/problems/climbing-stairs 15 | 16 | 思路分析:实际上和「斐波那契数列」问题一样,f(n)=f(n-1)+f(n-2) 17 | 18 | 状态转换方程:当前走法 = 走一步走法 + 走两步走法。 19 | 20 | 正难则反,从第一层结果往上推导 21 | ```java 22 | class Solution { 23 | public int climbStairs(int n) { 24 | int f1 = 1, f2 = 1,count=1; // 初始化第一层走法,f1、f2 分别记录走一步走法和走两步走法 25 | for (int i = 2; i <= n; i++) { 26 | count = f1 + f2; 27 | f2 = f1; 28 | f1 = count; // 更新走一步走法、走两步走法 29 | } 30 | return count; 31 | } 32 | } 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /LeetCode72. 编辑距离.md: -------------------------------------------------------------------------------- 1 | # 编辑距离 2 | >给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。 3 | 你可以对一个单词进行如下三种操作: 4 | 插入一个字符 5 | 删除一个字符 6 | 替换一个字符 7 | 8 | >示例 1: 9 | 输入: word1 = "horse", word2 = "ros" 10 | 输出: 3 11 | 解释: 12 | horse -> rorse (将 'h' 替换为 'r') 13 | rorse -> rose (删除 'r') 14 | rose -> ros (删除 'e') 15 | 16 | >来源:力扣(LeetCode) 17 | 链接:https://leetcode-cn.com/problems/edit-distance 18 | 19 | 思路分析: 20 | 1. min[i][j] i,j 分别代表 word1、word2 索引,遍历至 min[i][j] 会出现两种情况,word1、word2 当前遍历字符相等 / 不相等 21 | 2. 当前遍历字符相等,word1[i-1] == word2[j-1] 则当前操作次数与前一位操作次数相等 22 | 3. 当前遍历字符不相等,word1[i-1]!= word2[j-1] 则当前操作次数 = min(删除、插入、替换)+1 23 | 4. min[i-1,j] 代表删除字符,min[i][j-1] 代表插入字符,min[i-1][i-1] 代表替换字符 24 | ```java 25 | class Solution { 26 | public int minDistance(String word1, String word2) { 27 | if (word1 == null || word2 == null) { 28 | return word1 == null ? word2.length() : word1.length(); 29 | } 30 | if (word1.equals(word2)) { 31 | return 0; 32 | } 33 | int len1 = word1.length(), len2 = word2.length(); 34 | int[][] min = new int[len1 + 1][len2 + 1]; 35 | // 初始化 min 36 | for (int i = 0; i <= len1; i++) { 37 | min[i][0] = i; 38 | } 39 | for (int i = 0; i <= len2; i++) { 40 | min[0][i] = i; 41 | } 42 | for (int i = 1; i <= len1; i++) { 43 | for (int j = 1; j <= len2; j++) { 44 | if (word1.charAt(i-1) == word2.charAt(j-1)) { 45 | min[i][j] = min[i - 1][j - 1]; 46 | } else { 47 | int minValue = min[i - 1][j - 1]; 48 | minValue = minValue > min[i - 1][j] ? min[i - 1][j]:minValue; 49 | minValue = minValue > min[i][j - 1] ? min[i][j - 1] : minValue; 50 | min[i][j] = minValue+1; 51 | } 52 | } 53 | } 54 | return min[len1][len2]; 55 | } 56 | } 57 | ``` 58 | 59 | -------------------------------------------------------------------------------- /LeetCode724. 寻找数组的中心索引.md: -------------------------------------------------------------------------------- 1 | # LeetCode724. 寻找数组的中心索引 2 | 3 | #### [724. 寻找数组的中心索引](https://leetcode-cn.com/problems/find-pivot-index/) 4 | 5 | 注:本题无法使用双指针法,因为无法确定何时该移动左右指针 6 | 7 | 解法一:暴力法,依次枚举每次遍历坐标是否满足中心索引要求 8 | 9 | ```java 10 | public int pivotIndex(int[] nums) { 11 | for (int i = 0; i < nums.length; i++) { 12 | if (sum(nums, 0, i) == sum(nums, i + 1, nums.length)) { 13 | return i; 14 | } 15 | } 16 | return -1; 17 | } 18 | 19 | private long sum(int[] nums, int starIndex, int endIndex) { 20 | int total = 0; 21 | for (int i = starIndex; i < endIndex; i++) { 22 | total += nums[i]; 23 | } 24 | return total; 25 | } 26 | ``` 27 | 28 | 解法二:前缀和 参考[官方题解](https://leetcode-cn.com/problems/find-pivot-index/solution/xun-zhao-shu-zu-de-zhong-xin-suo-yin-by-gzjle/) 29 | 30 | 在暴力法的基础上优化,先一次遍历计算整个 nums 的元素和 31 | 32 | 第二次从左到右遍历,若 sum-nums[i]=prefixSum*2 ,说明当前遍历坐标为中心索引 ,否则加入当前遍历元素值继续遍历下一元素。 33 | 34 | ```java 35 | public int pivotIndex(int[] nums) { 36 | int sum = 0, prefixSum = 0; 37 | for (int num : nums) { 38 | sum += num; 39 | } 40 | for (int i = 0; i < nums.length; i++) { 41 | if (sum - nums[i] == 2 * prefixSum) { 42 | return i; 43 | } 44 | prefixSum += nums[i]; 45 | } 46 | return -1; 47 | } 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /LeetCode746.使用最小花费爬楼梯.md: -------------------------------------------------------------------------------- 1 | # LeetCode746.使用最小花费爬楼梯 2 | 3 | #### [746. 使用最小花费爬楼梯](https://leetcode-cn.com/problems/min-cost-climbing-stairs/) 4 | 5 | 解题思路:动态规划 6 | 7 | 当前楼梯最小值=Math.min(前一步最小值,前两步最小值) 8 | 9 | ```java 10 | public int minCostClimbingStairs(int[] cost) { 11 | int n = cost.length; 12 | int[] min = new int[n]; 13 | min[0] = cost[0]; 14 | min[1] = cost[1]; 15 | for (int i = 2; i < n; i++) { 16 | min[i] = Math.min(min[i - 1], min[i - 2]) + cost[i]; 17 | } 18 | return Math.min(min[n - 1], min[n - 2]); 19 | } 20 | ``` 21 | 22 | 简化 minN1、minN2 分别记录 前一步最小值,前两步最小值 23 | 24 | ```java 25 | public int minCostClimbingStairs(int[] cost) { 26 | int n = cost.length; 27 | int minN1 = cost[0]; 28 | int minN2 = cost[1]; 29 | for (int i = 2; i < n; i++) { 30 | int next= Math.min(minN1, minN2) + cost[i]; 31 | minN2 = minN1; 32 | minN1 = next; 33 | } 34 | return Math.min(minN1, minN2); 35 | } 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /LeetCode75. 颜色分类.md: -------------------------------------------------------------------------------- 1 | # 颜色分类 2 | >给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 3 | 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 4 | 注意: 5 | 不能使用代码库中的排序函数来解决这道题。 6 | 7 | >示例: 8 | 输入: [2,0,2,1,1,0] 9 | 输出: [0,0,1,1,2,2] 10 | 11 | >来源:力扣(LeetCode) 12 | 链接:https://leetcode-cn.com/problems/sort-colors 13 | 14 | 思路分析:依序遍历 nums,遇到 0 ,从起始点开始放,遇到 2 从末尾开始放。 15 | 16 | ```java 17 | public void sortColors(int[] nums) { 18 | int start = 0, end = nums.length - 1, index = 0, 19 | RED = 0, BLUE = 2; 20 | while (index <= end) { 21 | if (nums[index] == RED) { 22 | swap(nums, start++, index++); // start 交换的值只可能为 0 和 1,所以不用进行二次比较 23 | } else if (nums[index] == BLUE) { 24 | swap(nums, end--, index); // 可能为 0,还需要再次比较 25 | } else { 26 | index++; 27 | } 28 | } 29 | } 30 | 31 | private void swap(int[] nums, int index1, int index2) { 32 | int temp = nums[index1]; 33 | nums[index1] = nums[index2]; 34 | nums[index2] = temp; 35 | } 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /LeetCode763. 划分字母区间.md: -------------------------------------------------------------------------------- 1 | # 划分字母区间 2 | >字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。 3 | 4 | >示例 1: 5 | 输入: S = "ababcbacadefegdehijhklij" 6 | 输出: [9,7,8] 7 | 解释: 8 | 划分结果为 "ababcbaca", "defegde", "hijhklij"。 9 | 每个字母最多出现在一个片段中。 10 | 像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。 11 | 12 | >来源:力扣(LeetCode) 13 | 链接:https://leetcode-cn.com/problems/partition-labels 14 | 15 | 思路分析: 16 | 17 | 1、lastIndex[] 记录 S 中每个字母出现的最大索引(最后出现位置) 18 | 19 | 2、 count 记录每一段分词长度 20 | 21 | 3、max 记录每一段分词字母出现的最大索引,当分词内所有字母最后出现索引 <= max 时,可以分词。 22 | ```java 23 | class Solution { 24 | public List partitionLabels(String S) { 25 | int[] lastIndex = new int[26]; // 存储 26 字母出现最大索引 26 | for (char c : S.toCharArray()) { // 记录所有字母最后出现位置 27 | lastIndex[c - 'a'] = S.lastIndexOf(c); 28 | } 29 | List result = new ArrayList<>(); // 存储分词长度 30 | int index = 0; 31 | while (index < S.length()) { 32 | int count = 0, max = lastIndex[S.charAt(index) - 'a']; // max 存储当前区间最大索引值 33 | for (int i = index; i <= max; i++) { // 当前区间所有字符都小于 max,达成分词条件 34 | count++; // 记录分词长度 35 | int curLastIndex = lastIndex[S.charAt(i) - 'a']; 36 | max = curLastIndex > max ? curLastIndex : max; // 更新 max 值 37 | } 38 | index = max + 1; // 更新索引 39 | result.add(count); // 加入结果集 40 | } 41 | return result; 42 | } 43 | } 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /LeetCode78. 子集.md: -------------------------------------------------------------------------------- 1 | # 78. 子集 [题目链接](https://leetcode-cn.com/problems/subsets/) 2 | 解法一:回溯法 3 | 4 | 依次创造 1...nums.length 长度的子数组 5 | 6 | createSubSet,创造子数组 7 | 8 | subSets 存储已生成子数组 9 | 10 | ```java 11 | private List> subSets = new ArrayList<>(); 12 | public List> subsets(int[] nums) { 13 | subSets.add(new ArrayList<>()); 14 | for (int i = 1; i <= nums.length; i++) { 15 | createSubSet(nums, 0, i, new ArrayList<>()); 16 | } 17 | return subSets; 18 | } 19 | 20 | private void createSubSet(int[] nums, int startIndex, int k, List subset) { 21 | if (subset.size() == k) { 22 | subSets.add(new ArrayList<>(subset)); 23 | return; 24 | } 25 | for (int i = startIndex ; i < nums.length; i++) { 26 | subset.add(nums[i]); 27 | createSubSet(nums, i+1, k, subset); 28 | subset.remove(subset.size() - 1); 29 | } 30 | } 31 | ``` 32 | 解法优化:用递归代替循环,用 Interge[] 替代 ArrayList,减少 remove()的时间复杂度。思路参考:https://leetcode.com/problems/subsets/discuss/543960/JAVA-0-ms-Recursive-solution 33 | 34 | ```java 35 | private List> subSets = new ArrayList<>(); 36 | public List> subsets(int[] nums) { 37 | subsetRec(nums, new Integer[nums.length], 0, 0); 38 | return subSets; 39 | } 40 | 41 | private void subsetRec(int[] nums, Integer[] arr, int index, int cur) { 42 | if (index < nums.length) { 43 | if (index == nums.length - 1) { 44 | subSets.add(Arrays.asList(Arrays.copyOfRange(arr, 0, cur))); 45 | } 46 | subsetRec(nums, arr, index + 1, cur); 47 | arr[cur] = nums[index]; 48 | if (index == nums.length - 1) { 49 | subSets.add(Arrays.asList(Arrays.copyOfRange(arr, 0, cur+1))); 50 | } 51 | subsetRec(nums, arr, index + 1, cur + 1); 52 | } 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /LeetCode8. 字符串转换整数 (atoi).md: -------------------------------------------------------------------------------- 1 | # 8. 字符串转换整数 (atoi) [题目链接](https://leetcode-cn.com/problems/string-to-integer-atoi/) 2 | 解题思路: 3 | 4 | 1、当 str 去除前端空格后,第一个字符不为数字、+、-,则直接返回 0 5 | 6 | 2、sign 记录正负号,默认为 +, 7 | 8 | 3、 当 sign 为 +,prefix = Integer.MAX_VALUE / 10 suffix = 7 9 | 10 | 4、 当 sign 为 -,prefix = Integer.MAX_VALUE / 10 suffix = 8 11 | 12 | 5、start 为有效位起始索引,end 为结束索引,从起始位每遍历一个数字 end++ 13 | 14 | 6、 result 记录转换后的数字,若 start==end 则 return 0 15 | 16 | ```java 17 | public int myAtoi(String str) { 18 | str = str.trim(); 19 | int start = 0; 20 | boolean sign = true; 21 | if (str.length() > 0 && (str.charAt(start) == '-' || str.charAt(start) == '+')) { 22 | sign = str.charAt(start) == '+' ? true : false; 23 | start++; 24 | } 25 | int prefix = Integer.MAX_VALUE / 10, suffix; 26 | if (sign) { 27 | suffix = 7; 28 | } else { 29 | suffix = 8; 30 | } 31 | int end = start, result = 0; 32 | while (end < str.length() && str.charAt(end) <= '9' && str.charAt(end) >= '0') { 33 | // 超出 int 范围 34 | if (result > prefix || (result == prefix && suffix <= str.charAt(end) - '0')) { 35 | return sign ? Integer.MAX_VALUE : Integer.MIN_VALUE; 36 | } 37 | result = result * 10 + str.charAt(end++) - '0'; 38 | } 39 | return sign ? result : -result; 40 | } 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /LeetCode82. 删除排序链表中的重复元素 II.md: -------------------------------------------------------------------------------- 1 | # LeetCode82. 删除排序链表中的重复元素 II 2 | 3 | #### [82. 删除排序链表中的重复元素 II](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/) 4 | 5 | 解题思路:哨兵节点 6 | 7 | lastValue 记录上一节点值,pre 代表上一节点,curr 代表当前节点, next代表下一节点 8 | 9 | 依次遍历链表,判断当前节点是否应该被删除:(pre.next= curr.next) 10 | 11 | 1、当前节点值与上一节点值相同,curr.val=lastValue 12 | 13 | 2、当前节点存在下一节点,且下一节点值与当前节点值相等 14 | 15 | ```java 16 | public ListNode deleteDuplicates(ListNode head) { 17 | ListNode node = new ListNode(-1); 18 | node.next = head; 19 | ListNode pre = node, curr = node.next; 20 | int lastValue = node.val; 21 | while (curr != null) { 22 | // 当前节点应当被删除 23 | if (lastValue == curr.val || (curr.next != null && curr.next.val == curr.val)) { 24 | lastValue = curr.val; 25 | pre.next = curr.next; 26 | } else { 27 | pre = pre.next; 28 | } 29 | curr = curr.next; 30 | } 31 | return node.next; 32 | } 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /LeetCode830. 较大分组的位置.md: -------------------------------------------------------------------------------- 1 | # LeetCode830. 较大分组的位置 2 | 3 | #### [830. 较大分组的位置](https://leetcode-cn.com/problems/positions-of-large-groups/) 4 | 5 | 解题思路:一次遍历 6 | 7 | 1、依序遍历 s,每遍历不同字符,记录分组长度 8 | 9 | 2、若分组长度大于等于 3 ,存储起始索引与结束索引 10 | 11 | ```java 12 | public List> largeGroupPositions(String s) { 13 | List> resultList = new ArrayList<>(); 14 | int index = 0; 15 | while (index < s.length()) { 16 | int startIndex = index; 17 | while (index < s.length() && s.charAt(index) == s.charAt(startIndex)) { 18 | index++; 19 | } 20 | if (index - startIndex >= 3) { 21 | resultList.add(Arrays.asList(startIndex, index - 1)); 22 | } 23 | } 24 | return resultList; 25 | } 26 | ``` 27 | 28 | -------------------------------------------------------------------------------- /LeetCode836. 矩形重叠.md: -------------------------------------------------------------------------------- 1 | # 836. 矩形重叠 [题目链接](https://leetcode-cn.com/problems/rectangle-overlap/) 2 | 解法一: 3 | 4 | **正难则反**,若 rec1 与 rec2 不相交,则 rec1 四条边都应该在 rec2 外部。 5 | 6 | rec1 位于 rec2 左侧,rec1[2]<=rec2[0], 7 | rec1 位于 rec2 右侧,rec2[2]<=rec1[0], 8 | rec1 位于 rec2 上侧,rec2[3]<=rec1[1], 9 | rec1 位于 rec2 下侧,rec1[3]<=rec2[1]。 10 | 11 | ```java 12 | public boolean isRectangleOverlap(int[] rec1, int[] rec2) { 13 | return !(rec1[2]<=rec2[0]||rec2[2]<=rec1[0]||rec2[3]<=rec1[1]||rec1[3]<=rec2[1]); 14 | } 15 | ``` 16 | 解法二:若 rec1、rec2 重叠,则二者重叠部分必为矩形 ==> rec1、rec2 在 x 轴 y 轴上投影必然同时有重叠. 17 | 18 | ```java 19 | public boolean isRectangleOverlap(int[] rec1, int[] rec2) { 20 | return Math.min(rec1[2], rec2[2]) > Math.max(rec1[0], rec2[0]) && 21 | Math.min(rec1[3], rec2[3]) > Math.max(rec1[1], rec2[1]); 22 | } 23 | ``` 24 | 题解参考:https://leetcode-cn.com/problems/rectangle-overlap/solution/ju-xing-zhong-die-by-leetcode-solution/ 25 | 26 | 27 | -------------------------------------------------------------------------------- /LeetCode84. 柱状图中最大的矩形.md: -------------------------------------------------------------------------------- 1 | # 柱状图中最大的矩形 2 | 3 | ## 解法一,暴力法 4 | 思路分析:当前柱子所能形成的最大面积=到结束点柱子(left~right)最低高度 * 索引差(宽度) 5 | max 记录所能达到的最大面积 6 | ```java 7 | public int largestRectangleArea(int[] heights) { 8 | if (heights == null || heights.length < 1) { 9 | return 0; 10 | } 11 | int max = heights[0]; 12 | for (int left = 0; left < heights.length; left++) { 13 | int minHeight = heights[left]; 14 | for (int right = left; right < heights.length; right++) { 15 | minHeight = Math.min(minHeight, heights[right]); 16 | max = Math.max(max, minHeight * (right - left + 1)); 17 | } 18 | } 19 | return max; 20 | } 21 | ``` 22 | 23 | ## 解法二,栈 24 | 思路分析: 25 | 26 | 基于解法一,当前柱子所能形成的最大面积=到结束点柱子(left~right)最低高度 * 索引差(宽度) 27 | 28 | 所以,当遍历下一柱子时,我们有两种可能: 29 | 30 | 1、柱子高度递减(或保持不变),我们需要重新记录最低柱子高度 31 | 32 | 2、柱子高度递增,记录最新柱子的高度。 33 | 34 | stack 存储递增柱子索引,先压栈 -1 方便计算宽度(索引差),遍历结束后,计算所有递增柱所能围成的最大面积,max 记录所能围成的最大面积 35 | ```java 36 | public int largestRectangleArea(int[] heights) { 37 | if (heights == null || heights.length < 1) { 38 | return 0; 39 | } 40 | int max = 0; 41 | Stack stack = new Stack<>(); 42 | stack.push(-1); // 占位 43 | for (int i = 0; i < heights.length; i++) { 44 | while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) { // 柱子高度递减(或保持不变) 45 | max = Math.max(max, heights[stack.pop()] * (i-stack.peek()-1)); 46 | } 47 | stack.push(i); 48 | } 49 | while (stack.peek() != -1) { 50 | max = Math.max(max, heights[stack.pop()] * (heights.length - stack.peek()-1)); 51 | } 52 | return max; 53 | } 54 | ``` 55 | 56 | 思路参考:[官方题解](https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/zhu-zhuang-tu-zhong-zui-da-de-ju-xing-by-leetcode/) 57 | 58 | -------------------------------------------------------------------------------- /LeetCode85. 最大矩形.md: -------------------------------------------------------------------------------- 1 | # LeetCode85. 最大矩形 2 | 3 | #### [85. 最大矩形](https://leetcode-cn.com/problems/maximal-rectangle/) 4 | 5 | 解题思路:暴力解题 6 | 7 | 1、首次遍历,记录当前座标所能围成的最大宽度(横向连续为 1 的数量) 8 | 9 | 2、第二次遍历,获取当前坐标所能围成的最大高度(纵向连续为 1 的数量),当前所能围成最大矩形面积为 最小宽度*高度 10 | 11 | 3、maxRectangle 记录最大矩形面积 12 | 13 | ```java 14 | public int maximalRectangle(char[][] matrix) { 15 | if (matrix.length < 1) { 16 | return 0; 17 | } 18 | int maxRectangle = 0, rowLen = matrix.length, colLen = matrix[0].length; 19 | int[][] maxWidth = new int[rowLen][colLen]; 20 | // 初始化最大宽度 21 | for (int i = 0; i < rowLen; i++) { 22 | for (int j = 0; j < colLen; j++) { 23 | if (matrix[i][j] == '1') { 24 | maxWidth[i][j] = j == 0 ? 1 : maxWidth[i][j - 1] + 1; 25 | } 26 | } 27 | } 28 | // 计算最大矩形面积 29 | for (int row = 0; row < rowLen; row++) { 30 | for (int col = 0; col < colLen; col++) { 31 | if (matrix[row][col] == '0') { 32 | continue; 33 | } 34 | int area = maxWidth[row][col]; 35 | int minWight = maxWidth[row][col]; 36 | for (int i = row - 1; i >= 0; i--) { 37 | minWight = Math.min(minWight, maxWidth[i][col]); 38 | area = Math.max(area, minWight * (row - i + 1)); 39 | } 40 | maxRectangle = Math.max(maxRectangle, area); 41 | } 42 | } 43 | return maxRectangle; 44 | } 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /LeetCode86. 分隔链表.md: -------------------------------------------------------------------------------- 1 | # LeetCode86. 分隔链表 2 | 3 | #### [86. 分隔链表](https://leetcode-cn.com/problems/partition-list/) 4 | 5 | 解题思路: 6 | 7 | 1、lessXHead、otherHead 代表两链表头结点(**使用哨兵节点**) ,node1、node2 分别代表两链表当前节点 8 | 9 | 3、依序遍历 head 若当前节点值小于x则 node1 下一节点指向当前节点 node1=node1.next 10 | 11 | 4、若当前节点值大于等于 x 则 node2 下一节点指向当前节点 node2=node2.next 12 | 13 | 5、遍历结束,拼接两节点 node1.next=otherHead.next 返回 lessXHead.next 14 | 15 | ```java 16 | public ListNode partition(ListNode head, int x) { 17 | // 使用哨兵节点,减少空指针处理 18 | ListNode lessXHead = new ListNode(0); 19 | ListNode otherHead = new ListNode(0); 20 | ListNode node1 = lessXHead; 21 | ListNode node2 = otherHead; 22 | while (head != null) { 23 | ListNode node = head; 24 | head = head.next; 25 | // 每次将两条链表的下一节点置为 null,防止链表死循环 26 | node.next = null; 27 | if (node.val < x) { 28 | node1.next = node; 29 | node1 = node1.next; 30 | } else { 31 | node2.next = node; 32 | node2 = node2.next; 33 | } 34 | } 35 | // 合并链表 36 | node1.next = otherHead.next; 37 | return lessXHead.next; 38 | } 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /LeetCode867. 转置矩阵.md: -------------------------------------------------------------------------------- 1 | # LeetCode867. 转置矩阵 2 | 3 | #### [867. 转置矩阵](https://leetcode-cn.com/problems/transpose-matrix/) 4 | 5 | 解题思路:按列遍历依次按行加入数据 6 | 7 | ```java 8 | public int[][] transpose(int[][] matrix) { 9 | int[][] result = new int[matrix[0].length][matrix.length]; 10 | for (int i = 0; i < matrix[0].length; i++) { 11 | for (int j = 0; j < matrix.length; j++) { 12 | result[i][j] = matrix[j][i]; 13 | } 14 | } 15 | return result; 16 | } 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /LeetCode876. 链表的中间结点.md: -------------------------------------------------------------------------------- 1 | # 876. 链表的中间结点 [题目链接](https://leetcode-cn.com/problems/middle-of-the-linked-list/) 2 | 解题思路:双指针法,快指针一次走两步,慢指针一次走一步,当快指针走完链表时,慢指针指向的就是中间节点。 3 | 4 | ```java 5 | public ListNode middleNode(ListNode head) { 6 | ListNode fast = head, slow = head; 7 | while (fast != null && fast.next != null) { 8 | fast = fast.next.next; 9 | slow = slow.next; 10 | } 11 | return slow; 12 | } 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /LeetCode888. 公平的糖果棒交换.md: -------------------------------------------------------------------------------- 1 | # LeetCode888. 公平的糖果棒交换 2 | 3 | #### [888. 公平的糖果棒交换](https://leetcode-cn.com/problems/fair-candy-swap/) 4 | 5 | 解题思路:哈希表法 6 | 7 | 1. 第一次遍历 A\B 计算二者的糖果差值 diff,同时以 B糖果值建立哈希表 8 | 2. diff/2= 求出平均差值 9 | 3. 依次枚举 A 糖果,当哈希表中存在 A[i]+diff 时返回该组合 10 | 11 | ```java 12 | public int[] fairCandySwap(int[] A, int[] B) { 13 | int diff = 0; 14 | Set set = new HashSet<>(10000); 15 | for (int i = 0; i < A.length; i++) { 16 | diff += A[i]; 17 | } 18 | for (int i = 0; i < B.length; i++) { 19 | diff -= B[i]; 20 | set.add(B[i]); 21 | } 22 | int[] result = new int[2]; 23 | diff /= 2; 24 | for (int a : A) { 25 | Integer key = a - diff; 26 | if (set.contains(key)) { 27 | result[0] = a; 28 | result[1] = key; 29 | break; 30 | } 31 | } 32 | return result; 33 | } 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /LeetCode892. 三维形体的表面积.md: -------------------------------------------------------------------------------- 1 | # 892. 三维形体的表面积 [题目链接](https://leetcode-cn.com/problems/surface-area-of-3d-shapes/) 2 | 解题思路: 3 | 4 | 总表面积 = 柱体表面积 - 重叠面积 5 | 6 | 每一个坐标点上的立方体可看作一个柱体(长方体),柱体上下两面面积一定存在,中间四面表面积受重叠影响,减去的面积为相邻坐标点更低柱体侧面积。 7 | 8 | 思路参考:https://leetcode-cn.com/problems/surface-area-of-3d-shapes/solution/shi-li-you-tu-you-zhen-xiang-jiang-jie-yi-kan-jiu-/ 9 | 10 | ```java 11 | public int surfaceArea(int[][] grid) { 12 | int sum = 0; 13 | for (int x = 0; x < grid.length; x++) { 14 | for (int y = 0; y < grid[x].length; y++) { 15 | if (grid[x][y] > 0) { 16 | sum += grid[x][y] * 4 + 2; 17 | sum -= x > 0 ? Math.min(grid[x - 1][y], grid[x][y]) * 2 : 0; 18 | sum -= y > 0 ? Math.min(grid[x][y - 1], grid[x][y]) * 2 : 0; 19 | } 20 | } 21 | } 22 | return sum; 23 | } 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /LeetCode896. 单调数列.md: -------------------------------------------------------------------------------- 1 | # LeetCode896. 单调数列 2 | 3 | #### [896. 单调数列](https://leetcode-cn.com/problems/monotonic-array/) 4 | 5 | 解题思路: 6 | 7 | 1、单调序列规则,一定满足 (A[A.length-1]-A[0])*(A[i]-A[i-1])>=0 8 | 9 | 2、特殊情况 A[A.length-1]-A[0]=0,则 A[i]-A[i-1] 必须也为 0 10 | 11 | 3、计算 sub=A[A.length-1]-A[0],从第二个元素开始遍历 A,依次判断是否满足单调规则 12 | 13 | ```java 14 | public boolean isMonotonic(int[] A) { 15 | int sub = A[A.length - 1] - A[0]; 16 | for (int i = 1; i < A.length; i++) { 17 | if ((sub == 0 && A[i] != A[i - 1]) || (sub * (A[i] - A[i - 1]) < 0)) { 18 | return false; 19 | } 20 | } 21 | return true; 22 | } 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /LeetCode9.回文数.md: -------------------------------------------------------------------------------- 1 | # 回文数 [题目链接](https://leetcode-cn.com/problems/palindrome-number/) 2 | 3 | > 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 4 | 5 | > 示例 1: 6 | > 输入: 121 输出: true 7 | 8 | >示例 2: 9 | > 输入: -121 输出: false 10 | > 解释: 从左向右读, 为 -121 。 11 | > 从右向左读, 为 121- 。 12 | > 因此它不是一个回文数。 13 | 14 | 初始写法,采用「推进」思想,将整数 x 从右到左放入新整数中,即「低位向高位推进」。 15 | 16 | 虽然答案通过,但是未考虑,推进后可能产生的新数溢出整数范围问题。 17 | 18 | ```java 19 | class Solution { 20 | public boolean isPalindrome(int x) { 21 | if(x<0) // 负数则直接返回 false 22 | { 23 | return false; 24 | } 25 | int newNum=x%10; // 初始化为 x 个位值 26 | int tempNum=x/10; // temp 存储 x 截取个位后的新值 27 | while(tempNum>0){ // 若 tempNum 为 0 则推进结束 28 | newNum=newNum*10+tempNum%10; 29 | tempNum/=10; 30 | } 31 | // System.out.println(x+","+newNum); 32 | if(newNum==x) // 推进后产生的新数与源数相等则 33 | { 34 | return true; 35 | } 36 | return false; 37 | } 38 | } 39 | ``` 40 | 参考 [LeetCode 中文版官方题解](https://leetcode-cn.com/problems/palindrome-number/solution/hui-wen-shu-by-leetcode/) 41 | 42 | 只需比较前半段和半段是否对称即可 43 | ```java 44 | class Solution { 45 | public boolean isPalindrome(int x) { 46 | if(x<0||(x%10==0&&x!=0)) // 为负数或个位为 0 则不构成回文数 47 | { 48 | return false; 49 | } 50 | int newNum=x%10; 51 | x/=10; 52 | while(x>newNum){ 53 | newNum=newNum*10+x%10; 54 | x/=10; 55 | } 56 | 57 | return x==newNum||x==newNum/10; // x 为偶数位回文数则左右对称相等,奇数位回文则以中位数对称相等 58 | } 59 | } 60 | ``` 61 | 62 | -------------------------------------------------------------------------------- /LeetCode914. 卡牌分组.md: -------------------------------------------------------------------------------- 1 | # 914. 卡牌分组 2 | 解题思路:遍历 deck 以每个非重复数字为 key,出现次数为 value 3 | 4 | 若所有的 value 存在最大公约数(大于 1),则返回 true,否则返回 false。 5 | 6 | ```java 7 | public boolean hasGroupsSizeX(int[] deck) { 8 | Map map = new HashMap<>(); 9 | for (int card : deck) { 10 | map.put(card, map.getOrDefault(card, 0) + 1); 11 | } 12 | int count = 1; 13 | boolean flag = false; 14 | for (Integer key : map.keySet()) { 15 | if (!flag) { 16 | count = map.get(key); 17 | flag = true; 18 | } else { 19 | count = gcd(count, map.get(key)); 20 | } 21 | if (count < 2) { 22 | return false; 23 | } 24 | } 25 | return count != 1; 26 | } 27 | 28 | /** 29 | * 求最大公约数 30 | */ 31 | private int gcd(int a, int b) { 32 | return a == 0 ? b : gcd(a % b, b); 33 | } 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /LeetCode945. 使数组唯一的最小增量.md: -------------------------------------------------------------------------------- 1 | # 945. 使数组唯一的最小增量 [题目链接](https://leetcode-cn.com/problems/minimum-increment-to-make-array-unique/) 2 | 解法一: 3 | 4 | 对数组 A 升序排序,count 记录需要操作的次数。 5 | 6 | 若 A[i]<=A[i-1],count+=A[i-1]+1-A[i],A[i]=A[i-1]+1。 7 | 8 | ```java 9 | public int minIncrementForUnique(int[] A) { 10 | Arrays.sort(A); 11 | int count = 0; 12 | for (int i = 1; i < A.length; i++) { 13 | if (A[i] <= A[i - 1]) { 14 | count += A[i - 1] + 1 - A[i]; 15 | A[i] = A[i - 1] + 1; 16 | } 17 | } 18 | return count; 19 | } 20 | ``` 21 | 解法二: 22 | 23 | 建立哈希表 set,存储数组无重复元素,count 记录操作次数 (使用 boolean[50000] 代替) 24 | 25 | 依序遍历数组 A,若元素在 set 中不存在则遍历下一元素 26 | 27 | 若已存在,则 元素值、count++,直到在 set中无重复再遍历下一元素 28 | 29 | ```java 30 | public int minIncrementForUnique(int[] A) { 31 | boolean[] used = new boolean[50000]; 32 | int count = 0, index = 0; 33 | while (index < A.length) { 34 | if (!used[A[index]]) { 35 | used[A[index]] = true; 36 | index++; 37 | } else { 38 | A[index]++; 39 | count++; 40 | } 41 | } 42 | return count; 43 | } 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /LeetCode989. 数组形式的整数加法.md: -------------------------------------------------------------------------------- 1 | # LeetCode989. 数组形式的整数加法 2 | 3 | #### [989. 数组形式的整数加法](https://leetcode-cn.com/problems/add-to-array-form-of-integer/) 4 | 5 | 解题思路:按序相加 6 | 7 | 1、carry 记录进位值 8 | 9 | 2、sum 记录 A 当前遍历值(超出索引则为 0)+ K 的个位值+ carry 10 | 11 | 3、每次将sum个位置放入结果集中,carry 更新为 sum 十分位值,K/=10 降位 12 | 13 | 4、当 A 遍历结束,K 和 carry 都为 0 时遍历结束 14 | 15 | ```java 16 | public List addToArrayForm(int[] A, int K) { 17 | List result = new ArrayList<>(); 18 | int carry = 0, index = A.length - 1; 19 | while (K > 0 || index >= 0 || carry > 0) { 20 | int sum = (index >=0 ? A[index] : 0) + K % 10 + carry; 21 | K /= 10; 22 | result.add(sum % 10); 23 | carry = sum / 10; 24 | index--; 25 | } 26 | Collections.reverse(result); 27 | return result; 28 | } 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /LeetCode999. 车的可用捕获量.md: -------------------------------------------------------------------------------- 1 | # 999. 车的可用捕获量 2 | 解题思路: 3 | 4 | 1、设白色车的坐标为 (x,y),白色车的行进路线为(0,x)、(x,7)、(0,y)、(y,7) 5 | 6 | 2、count 记录能捕获卒的最大数量,最小为0,最大为 4 7 | 8 | 3、当行进路程中遭遇 ‘P’(卒)或 ‘B’(象) 时停止前进,且在遭遇卒时 count++ 9 | ```java 10 | class Solution { 11 | public int numRookCaptures(char[][] board) { 12 | int count = 0, x = 0, y = 0; 13 | // 找到车的位置 14 | for (int i = 0; i < board.length; i++) { 15 | for (int j = 0; j < board[i].length; j++) { 16 | if (board[i][j] == 'R') { 17 | x=i; 18 | y = j; 19 | break; 20 | } 21 | } 22 | } 23 | int[] moveX = {-1, 1, 0, 0}; 24 | int[] moveY = {0, 0, -1, 1}; 25 | for (int i = 0; i < moveX.length; i++) { 26 | int indexX = x + moveX[i], 27 | indexY = y + moveY[i]; 28 | while (indexX >= 0 && indexX < 8 && indexY >= 0 && indexY < 8) { 29 | if (board[indexX][indexY] == 'B' || board[indexX][indexY] == 'p') { 30 | count = board[indexX][indexY] == 'p' ? count + 1 : count; 31 | break; 32 | } 33 | indexX += moveX[i]; 34 | indexY += moveY[i]; 35 | } 36 | } 37 | return count; 38 | } 39 | } 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /LeetCode· 88. 合并两个有序数组.md: -------------------------------------------------------------------------------- 1 | # 合并两个有序数组 [题目链接](https://leetcode-cn.com/problems/merge-sorted-array/) 2 | 3 | > 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 4 | 5 | >说明: 6 | >初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 7 | 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 8 | 9 | >示例: 10 | >输入: 11 | nums1 = [1,2,3,0,0,0], m = 3 12 | nums2 = [2,5,6], n = 3 13 | 输出: [1,2,2,3,5,6] 14 | 15 | 解题思路: 16 | 17 | 1、创建一个可以容纳两个数组有效元素的数组,再将两个数组中的数按照从大到小存储到新数组,再重新放入 nums1 。(不推荐占用了多余的内存空间) 18 | 19 | 2、推荐:将两个数组从后往前排序,每次将最大的数放入 nums1 末尾。( 题目中有提示 :nums1 有足够的空间容纳两个数组中的有效元素) 20 | ```c 21 | void merge(int* nums1, int m, int* nums2, int n) { 22 | int i = 0, 23 | index_nums1=m-1, 24 | index_nums2=n-1, 25 | sum=m+n; 26 | while (i < sum) 27 | { 28 | i++; 29 | if (index_nums1 < 0) 30 | nums1[sum - i] = nums2[index_nums2--]; 31 | else if (index_nums2 < 0) 32 | break; 33 | else if (nums1[index_nums1] > nums2[index_nums2]) 34 | nums1[sum - i] = nums1[index_nums1--]; 35 | else 36 | nums1[sum - i] = nums2[index_nums2--]; 37 | } 38 | 39 | } 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /LeetCode面试题 01.07. 旋转矩阵.md: -------------------------------------------------------------------------------- 1 | # 面试题 01.07. 旋转矩阵 [题目链接](https://leetcode-cn.com/problems/rotate-matrix-lcci/) 2 | 解题思路:顺时针旋转 90° 对应转换规则 (x,y)->(y,n-x) ,n=N-1 3 | 4 | ```java 5 | public void rotate(int[][] matrix) { 6 | if (matrix == null || matrix.length < 1) { 7 | return; 8 | } 9 | int n = matrix.length - 1; 10 | int[][] tempMatrix = new int[matrix.length][matrix.length]; 11 | for (int i = 0; i < matrix.length; i++) { 12 | for (int j = 0; j < matrix[i].length; j++) { 13 | tempMatrix[i][j] = matrix[n-j][i]; 14 | } 15 | } 16 | for (int i = 0; i < matrix.length; i++) { 17 | matrix[i] = tempMatrix[i]; 18 | } 19 | } 20 | ``` 21 | 解法2:不借助辅助空间,先按对角线(右上角-左下角)对称交换值,在上下对称交换值 22 | 23 | ```java 24 | public void rotate(int[][] matrix) { 25 | if (matrix == null || matrix.length < 1) { 26 | return; 27 | } 28 | int n = matrix.length - 1; 29 | // 对角线交换:(x,y)->(n-y,n-x) 30 | for (int row = 0; row < n; row++) { 31 | for (int col = 0; col < n - row; col++) { 32 | swap(matrix, row, col, n - col, n - row); 33 | } 34 | } 35 | // 上下交换:(x,y)->(n-x,n-y) 36 | for (int row = 0; row < matrix.length / 2; row++) { 37 | for (int col = 0; col < matrix.length; col++) { 38 | swap(matrix, row, col, n - row, col); 39 | } 40 | } 41 | } 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /LeetCode面试题62. 圆圈中最后剩下的数字.md: -------------------------------------------------------------------------------- 1 | # 面试题62. 圆圈中最后剩下的数字 2 | 解法一:暴力枚举 3 | 4 | 以 new ArrayList<>(n) 模拟圆圈,每次移除 圆圈中按顺序数到的第 m 个数,最后剩余的那个数就是我们需要找的数。 5 | 6 | ```java 7 | public int lastRemaining(int n, int m) { 8 | List cycle = new ArrayList<>(n); 9 | for (int i = 0; i < n; i++) { 10 | cycle.add(i); 11 | } 12 | int startIndex = 0; 13 | while (n > 1) { 14 | startIndex = (startIndex + m-1) % cycle.size(); 15 | cycle.remove(startIndex); 16 | n--; 17 | } 18 | return cycle.get(0); 19 | } 20 | ``` 21 | 解法二:递归 22 | 23 | n 个数以 m 报数,最后一个数位置 = (n 个数以 m 报数的最后位置)+ m --> 写作 (m + len) 24 | 25 | 因为 (m + len) 可能超出 n,需要取余数 (m + len) % n 26 | 27 | ```java 28 | public int lastRemaining(int n, int m) { 29 | int index = 0; 30 | for (int i = 2; i <= n; i++) { 31 | index = (m + index) % i; 32 | } 33 | return recursive(n, m); 34 | } 35 | 36 | private int recursive(int n, int m) { 37 | if (n == 1) { 38 | return 0; 39 | } 40 | int len = recursive(n - 1, m); 41 | return (m + len) % n; 42 | } 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeetCode 2 | 我会在这里存放我的 LeetCode 刷题代码 3 | 4 | 同时记录我数据结构与算法的学习过程 5 | 6 | ![常见数据结构与算法以及解法](img/数据结构与算法.png) 7 | 8 | 如果感兴趣你也可以关注我的另一个项目《[剑指 offer 攻略](https://github.com/hackhu2019/offer)》:https://github.com/hackhu2019/offer 9 | 10 | 如果你想系统性的学习数据结构与算法相关的知识推荐你购买王争老师的专栏《[数据结构与算法之美](https://time.geekbang.org/column/intro/126)》:https://time.geekbang.org/column/intro/126 11 | 12 | ## [Thanks for free JetBrains Open Source license](https://jb.gg/OpenSource) 13 | 14 | ![JetBrains Open Source license](/img/jetbrains.png) -------------------------------------------------------------------------------- /[26]删除有序数组中的重复项.java: -------------------------------------------------------------------------------- 1 | //给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 2 | //。 3 | // 4 | // 由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个 5 | //元素应该保存最终结果。 6 | // 7 | // 将最终结果插入 nums 的前 k 个位置后返回 k 。 8 | // 9 | // 不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 10 | // 11 | // 判题标准: 12 | // 13 | // 系统会用下面的代码来测试你的题解: 14 | // 15 | // 16 | //int[] nums = [...]; // 输入数组 17 | //int[] expectedNums = [...]; // 长度正确的期望答案 18 | // 19 | //int k = removeDuplicates(nums); // 调用 20 | // 21 | //assert k == expectedNums.length; 22 | //for (int i = 0; i < k; i++) { 23 | // assert nums[i] == expectedNums[i]; 24 | //} 25 | // 26 | // 如果所有断言都通过,那么您的题解将被 通过。 27 | // 28 | // 29 | // 30 | // 示例 1: 31 | // 32 | // 33 | //输入:nums = [1,1,2] 34 | //输出:2, nums = [1,2,_] 35 | //解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。 36 | // 37 | // 38 | // 示例 2: 39 | // 40 | // 41 | //输入:nums = [0,0,1,1,1,2,2,3,3,4] 42 | //输出:5, nums = [0,1,2,3,4] 43 | //解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。 44 | // 45 | // 46 | // 47 | // 48 | // 提示: 49 | // 50 | // 51 | // 0 <= nums.length <= 3 * 10⁴ 52 | // -10⁴ <= nums[i] <= 10⁴ 53 | // nums 已按 升序 排列 54 | // 55 | // Related Topics 数组 双指针 👍 2492 👎 0 56 | 57 | 58 | //leetcode submit region begin(Prohibit modification and deletion) 59 | class Solution { 60 | public int removeDuplicates(int[] nums) { 61 | if (nums.length == 0) { 62 | return 0; 63 | } 64 | int low = 0, fast = 1; 65 | while (fast < nums.length) { 66 | if (nums[fast] != nums[low]) { 67 | low++; 68 | nums[low] = nums[fast]; 69 | } 70 | fast++; 71 | } 72 | return low + 1; 73 | } 74 | } 75 | //leetcode submit region end(Prohibit modification and deletion) 76 | -------------------------------------------------------------------------------- /[27]移除元素.java: -------------------------------------------------------------------------------- 1 | //给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 2 | // 3 | // 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 4 | // 5 | // 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 6 | // 7 | // 8 | // 9 | // 说明: 10 | // 11 | // 为什么返回数值是整数,但输出的答案是数组呢? 12 | // 13 | // 请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 14 | // 15 | // 你可以想象内部操作如下: 16 | // 17 | // 18 | //// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 19 | //int len = removeElement(nums, val); 20 | // 21 | //// 在函数里修改输入数组对于调用者是可见的。 22 | //// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。 23 | //for (int i = 0; i < len; i++) { 24 | // print(nums[i]); 25 | //} 26 | // 27 | // 28 | // 29 | // 30 | // 示例 1: 31 | // 32 | // 33 | //输入:nums = [3,2,2,3], val = 3 34 | //输出:2, nums = [2,2] 35 | //解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 36 | //nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。 37 | // 38 | // 39 | // 示例 2: 40 | // 41 | // 42 | //输入:nums = [0,1,2,2,3,0,4,2], val = 2 43 | //输出:5, nums = [0,1,4,0,3] 44 | //解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面 45 | //的元素。 46 | // 47 | // 48 | // 49 | // 50 | // 提示: 51 | // 52 | // 53 | // 0 <= nums.length <= 100 54 | // 0 <= nums[i] <= 50 55 | // 0 <= val <= 100 56 | // 57 | // Related Topics 数组 双指针 👍 1208 👎 0 58 | 59 | 60 | //leetcode submit region begin(Prohibit modification and deletion) 61 | class Solution { 62 | public int removeElement(int[] nums, int val) { 63 | if (nums.length == 0) { 64 | return 0; 65 | } 66 | int low = 0, fast = 0; 67 | while (fast < nums.length) { 68 | if (nums[fast] != val) { 69 | nums[low] = nums[fast]; 70 | low++; 71 | } 72 | fast++; 73 | } 74 | return low; 75 | } 76 | } 77 | //leetcode submit region end(Prohibit modification and deletion) 78 | -------------------------------------------------------------------------------- /[283]移动零.java: -------------------------------------------------------------------------------- 1 | //给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 2 | // 3 | // 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 4 | // 5 | // 6 | // 7 | // 示例 1: 8 | // 9 | // 10 | //输入: nums = [0,1,0,3,12] 11 | //输出: [1,3,12,0,0] 12 | // 13 | // 14 | // 示例 2: 15 | // 16 | // 17 | //输入: nums = [0] 18 | //输出: [0] 19 | // 20 | // 21 | // 22 | // 提示: 23 | // 24 | // 25 | // 26 | // 1 <= nums.length <= 10⁴ 27 | // -2³¹ <= nums[i] <= 2³¹ - 1 28 | // 29 | // 30 | // 31 | // 32 | // 进阶:你能尽量减少完成的操作次数吗? 33 | // Related Topics 数组 双指针 👍 1472 👎 0 34 | 35 | 36 | //leetcode submit region begin(Prohibit modification and deletion) 37 | class Solution { 38 | public void moveZeroes(int[] nums) { 39 | // 依次遍历数组,慢指针存放当前非零数据索引,快指针遍历非零数据 40 | if (nums.length == 0) { 41 | return; 42 | } 43 | int fast = 0, low = 0; 44 | while (fast < nums.length){ 45 | if (nums[fast] != 0) { 46 | int temp= nums[low]; 47 | nums[low] = nums[fast]; 48 | nums[fast] = temp; 49 | low++; 50 | } 51 | fast++; 52 | } 53 | } 54 | } 55 | //leetcode submit region end(Prohibit modification and deletion) 56 | -------------------------------------------------------------------------------- /[5]最长回文子串.java: -------------------------------------------------------------------------------- 1 | //给你一个字符串 s,找到 s 中最长的回文子串。 2 | // 3 | // 4 | // 5 | // 示例 1: 6 | // 7 | // 8 | //输入:s = "babad" 9 | //输出:"bab" 10 | //解释:"aba" 同样是符合题意的答案。 11 | // 12 | // 13 | // 示例 2: 14 | // 15 | // 16 | //输入:s = "cbbd" 17 | //输出:"bb" 18 | // 19 | // 20 | // 21 | // 22 | // 提示: 23 | // 24 | // 25 | // 1 <= s.length <= 1000 26 | // s 仅由数字和英文字母组成 27 | // 28 | // Related Topics 字符串 动态规划 👍 4832 👎 0 29 | 30 | 31 | //leetcode submit region begin(Prohibit modification and deletion) 32 | class Solution { 33 | public String longestPalindrome(String s) { 34 | String longest = ""; 35 | for (int i = 0; i < s.length(); i++) { 36 | String oddStr = palindrome(s, i, i); 37 | String evenStr = palindrome(s, i, i + 1); 38 | longest = oddStr.length() > longest.length() ? oddStr : longest; 39 | longest = evenStr.length() > longest.length() ? evenStr : longest; 40 | } 41 | return longest; 42 | } 43 | 44 | // 寻找以当前左右指针为中心的最长回文字串 45 | private String palindrome(String s, int left, int right) { 46 | while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) { 47 | left--; 48 | right++; 49 | } 50 | return s.substring(left+1, right); 51 | } 52 | } 53 | //leetcode submit region end(Prohibit modification and deletion) 54 | -------------------------------------------------------------------------------- /[83]删除排序链表中的重复元素.java: -------------------------------------------------------------------------------- 1 | //给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 2 | // 3 | // 4 | // 5 | // 示例 1: 6 | // 7 | // 8 | //输入:head = [1,1,2] 9 | //输出:[1,2] 10 | // 11 | // 12 | // 示例 2: 13 | // 14 | // 15 | //输入:head = [1,1,2,3,3] 16 | //输出:[1,2,3] 17 | // 18 | // 19 | // 20 | // 21 | // 提示: 22 | // 23 | // 24 | // 链表中节点数目在范围 [0, 300] 内 25 | // -100 <= Node.val <= 100 26 | // 题目数据保证链表已经按升序 排列 27 | // 28 | // Related Topics 链表 👍 739 👎 0 29 | 30 | 31 | //leetcode submit region begin(Prohibit modification and deletion) 32 | /** 33 | * Definition for singly-linked list. 34 | * public class ListNode { 35 | * int val; 36 | * ListNode next; 37 | * ListNode() {} 38 | * ListNode(int val) { this.val = val; } 39 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 40 | * } 41 | */ 42 | class Solution { 43 | public ListNode deleteDuplicates(ListNode head) { 44 | if (head == null || head.next == null) { 45 | return head; 46 | } 47 | ListNode low = head, fast = head.next; 48 | while (fast != null) { 49 | if (low.val != fast.val) { 50 | low.next = fast; 51 | low=low.next; 52 | } 53 | fast=fast.next; 54 | } 55 | low.next = fast; 56 | return head; 57 | } 58 | } 59 | //leetcode submit region end(Prohibit modification and deletion) 60 | -------------------------------------------------------------------------------- /img/jetbrains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackhu2019/LeetCode/672a41799423c4aba336ec73b5c265c2bb579bca/img/jetbrains.png -------------------------------------------------------------------------------- /img/数据结构与算法.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackhu2019/LeetCode/672a41799423c4aba336ec73b5c265c2bb579bca/img/数据结构与算法.png -------------------------------------------------------------------------------- /leetcode/editor/cn/[114]二叉树展开为链表.java: -------------------------------------------------------------------------------- 1 | //给你二叉树的根结点 root ,请你将它展开为一个单链表: 2 | // 3 | // 4 | // 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 5 | // 展开后的单链表应该与二叉树 先序遍历 顺序相同。 6 | // 7 | // 8 | // 9 | // 10 | // 示例 1: 11 | // 12 | // 13 | //输入:root = [1,2,5,3,4,null,6] 14 | //输出:[1,null,2,null,3,null,4,null,5,null,6] 15 | // 16 | // 17 | // 示例 2: 18 | // 19 | // 20 | //输入:root = [] 21 | //输出:[] 22 | // 23 | // 24 | // 示例 3: 25 | // 26 | // 27 | //输入:root = [0] 28 | //输出:[0] 29 | // 30 | // 31 | // 32 | // 33 | // 提示: 34 | // 35 | // 36 | // 树中结点数在范围 [0, 2000] 内 37 | // -100 <= Node.val <= 100 38 | // 39 | // 40 | // 41 | // 42 | // 进阶:你可以使用原地算法(O(1) 额外空间)展开这棵树吗? 43 | // Related Topics 栈 树 深度优先搜索 链表 二叉树 👍 1103 👎 0 44 | 45 | 46 | //leetcode submit region begin(Prohibit modification and deletion) 47 | 48 | import javax.swing.tree.TreeNode; 49 | 50 | /** 51 | * Definition for a binary tree node. 52 | * public class TreeNode { 53 | * int val; 54 | * TreeNode left; 55 | * TreeNode right; 56 | * TreeNode() {} 57 | * TreeNode(int val) { this.val = val; } 58 | * TreeNode(int val, TreeNode left, TreeNode right) { 59 | * this.val = val; 60 | * this.left = left; 61 | * this.right = right; 62 | * } 63 | * } 64 | */ 65 | class Solution { 66 | public void flatten(TreeNode root) { 67 | if (root == null) { 68 | return; 69 | } 70 | // 左右子树拉直 71 | flatten(root.left); 72 | flatten(root.right); 73 | // 左子树替换右子树 74 | TreeNode left = root.left; 75 | TreeNode right = root.right; 76 | root.left = null; 77 | root.right = left; 78 | // 子树末尾接入拉平的右子树 79 | TreeNode node = root; 80 | while (node.right != null) { 81 | node = node.right; 82 | } 83 | node.right = right; 84 | } 85 | } 86 | //leetcode submit region end(Prohibit modification and deletion) 87 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[141]环形链表.java: -------------------------------------------------------------------------------- 1 | //给你一个链表的头节点 head ,判断链表中是否有环。 2 | // 3 | // 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到 4 | //链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。 5 | // 6 | // 如果链表中存在环 ,则返回 true 。 否则,返回 false 。 7 | // 8 | // 9 | // 10 | // 示例 1: 11 | // 12 | // 13 | // 14 | // 15 | //输入:head = [3,2,0,-4], pos = 1 16 | //输出:true 17 | //解释:链表中有一个环,其尾部连接到第二个节点。 18 | // 19 | // 20 | // 示例 2: 21 | // 22 | // 23 | // 24 | // 25 | //输入:head = [1,2], pos = 0 26 | //输出:true 27 | //解释:链表中有一个环,其尾部连接到第一个节点。 28 | // 29 | // 30 | // 示例 3: 31 | // 32 | // 33 | // 34 | // 35 | //输入:head = [1], pos = -1 36 | //输出:false 37 | //解释:链表中没有环。 38 | // 39 | // 40 | // 41 | // 42 | // 提示: 43 | // 44 | // 45 | // 链表中节点的数目范围是 [0, 10⁴] 46 | // -10⁵ <= Node.val <= 10⁵ 47 | // pos 为 -1 或者链表中的一个 有效索引 。 48 | // 49 | // 50 | // 51 | // 52 | // 进阶:你能用 O(1)(即,常量)内存解决此问题吗? 53 | // Related Topics 哈希表 链表 双指针 👍 1396 👎 0 54 | 55 | 56 | //leetcode submit region begin(Prohibit modification and deletion) 57 | /** 58 | * Definition for singly-linked list. 59 | * class ListNode { 60 | * int val; 61 | * ListNode next; 62 | * ListNode(int x) { 63 | * val = x; 64 | * next = null; 65 | * } 66 | * } 67 | */ 68 | public class Solution { 69 | public boolean hasCycle(ListNode head) { 70 | // 快慢指针,快指针走一步,慢指针走两步,若相交则有环 71 | if (head == null || head.next == null) { 72 | return false; 73 | } 74 | ListNode fast = head.next.next, slow = head; 75 | while(fast != null && fast.next != null){ 76 | if (fast == slow) { 77 | return true; 78 | } 79 | slow = slow.next; 80 | fast = fast.next.next; 81 | } 82 | return false; 83 | } 84 | } 85 | //leetcode submit region end(Prohibit modification and deletion) 86 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[19]删除链表的倒数第 N 个结点.java: -------------------------------------------------------------------------------- 1 | //给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 2 | // 3 | // 4 | // 5 | // 示例 1: 6 | // 7 | // 8 | //输入:head = [1,2,3,4,5], n = 2 9 | //输出:[1,2,3,5] 10 | // 11 | // 12 | // 示例 2: 13 | // 14 | // 15 | //输入:head = [1], n = 1 16 | //输出:[] 17 | // 18 | // 19 | // 示例 3: 20 | // 21 | // 22 | //输入:head = [1,2], n = 1 23 | //输出:[1] 24 | // 25 | // 26 | // 27 | // 28 | // 提示: 29 | // 30 | // 31 | // 链表中结点的数目为 sz 32 | // 1 <= sz <= 30 33 | // 0 <= Node.val <= 100 34 | // 1 <= n <= sz 35 | // 36 | // 37 | // 38 | // 39 | // 进阶:你能尝试使用一趟扫描实现吗? 40 | // Related Topics 链表 双指针 👍 1861 👎 0 41 | 42 | 43 | //leetcode submit region begin(Prohibit modification and deletion) 44 | /** 45 | * Definition for singly-linked list. 46 | * public class ListNode { 47 | * int val; 48 | * ListNode next; 49 | * ListNode() {} 50 | * ListNode(int val) { this.val = val; } 51 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 52 | * } 53 | */ 54 | class Solution { 55 | public ListNode removeNthFromEnd(ListNode head, int n) { 56 | // 哨兵节点 57 | ListNode pre = new ListNode(-1); 58 | pre.next = head; 59 | // 双指针,快指针先走 N 步 60 | ListNode fast = pre, slow = pre; 61 | for (int i = 0; i <= n; i++) { 62 | fast = fast.next; 63 | } 64 | while (fast != null) { 65 | fast = fast.next; 66 | slow = slow.next; 67 | } 68 | slow.next = slow.next.next; 69 | return pre.next; 70 | } 71 | } 72 | //leetcode submit region end(Prohibit modification and deletion) 73 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[226]翻转二叉树.java: -------------------------------------------------------------------------------- 1 | //给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 2 | // 3 | // 4 | // 5 | // 示例 1: 6 | // 7 | // 8 | // 9 | // 10 | //输入:root = [4,2,7,1,3,6,9] 11 | //输出:[4,7,2,9,6,3,1] 12 | // 13 | // 14 | // 示例 2: 15 | // 16 | // 17 | // 18 | // 19 | //输入:root = [2,1,3] 20 | //输出:[2,3,1] 21 | // 22 | // 23 | // 示例 3: 24 | // 25 | // 26 | //输入:root = [] 27 | //输出:[] 28 | // 29 | // 30 | // 31 | // 32 | // 提示: 33 | // 34 | // 35 | // 树中节点数目范围在 [0, 100] 内 36 | // -100 <= Node.val <= 100 37 | // 38 | // Related Topics 树 深度优先搜索 广度优先搜索 二叉树 👍 1203 👎 0 39 | 40 | 41 | //leetcode submit region begin(Prohibit modification and deletion) 42 | 43 | import javax.swing.tree.TreeNode; 44 | 45 | /** 46 | * Definition for a binary tree node. 47 | * public class TreeNode { 48 | * int val; 49 | * TreeNode left; 50 | * TreeNode right; 51 | * TreeNode() {} 52 | * TreeNode(int val) { this.val = val; } 53 | * TreeNode(int val, TreeNode left, TreeNode right) { 54 | * this.val = val; 55 | * this.left = left; 56 | * this.right = right; 57 | * } 58 | * } 59 | */ 60 | class Solution { 61 | public TreeNode invertTree(TreeNode root) { 62 | if (root == null) { 63 | return root; 64 | } 65 | TreeNode tmp = root.left; 66 | root.left = root.right; 67 | root.right = tmp; 68 | invertTree(root.left); 69 | invertTree(root.right); 70 | return root; 71 | } 72 | } 73 | //leetcode submit region end(Prohibit modification and deletion) 74 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[22]括号生成.java: -------------------------------------------------------------------------------- 1 | //数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 2 | // 3 | // 4 | // 5 | // 示例 1: 6 | // 7 | // 8 | //输入:n = 3 9 | //输出:["((()))","(()())","(())()","()(())","()()()"] 10 | // 11 | // 12 | // 示例 2: 13 | // 14 | // 15 | //输入:n = 1 16 | //输出:["()"] 17 | // 18 | // 19 | // 20 | // 21 | // 提示: 22 | // 23 | // 24 | // 1 <= n <= 8 25 | // 26 | // Related Topics 字符串 动态规划 回溯 👍 2481 👎 0 27 | 28 | 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | 32 | //leetcode submit region begin(Prohibit modification and deletion) 33 | class Solution { 34 | 35 | public List generateParenthesis(int n) { 36 | List resultList = new ArrayList(n); 37 | traverse(resultList, n, n, new StringBuilder()); 38 | return resultList; 39 | } 40 | 41 | private void traverse(List resultList, int left, int right, StringBuilder str) { 42 | if (left < 0 || right < 0 || right < left) { 43 | return; 44 | } 45 | // 左右括号都用完,将 str 加入结果 46 | if (left == 0 && right == 0) { 47 | resultList.add(str.toString()); 48 | return; 49 | } 50 | str.append("("); 51 | traverse(resultList, left-1, right, str); 52 | str.deleteCharAt(str.length() - 1); 53 | str.append(")"); 54 | traverse(resultList, left, right - 1, str); 55 | str.deleteCharAt(str.length() - 1); 56 | } 57 | } 58 | //leetcode submit region end(Prohibit modification and deletion) 59 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[300]最长递增子序列.java: -------------------------------------------------------------------------------- 1 | //给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 2 | // 3 | // 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子 4 | //序列。 5 | // 6 | // 7 | // 示例 1: 8 | // 9 | // 10 | //输入:nums = [10,9,2,5,3,7,101,18] 11 | //输出:4 12 | //解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。 13 | // 14 | // 15 | // 示例 2: 16 | // 17 | // 18 | //输入:nums = [0,1,0,3,2,3] 19 | //输出:4 20 | // 21 | // 22 | // 示例 3: 23 | // 24 | // 25 | //输入:nums = [7,7,7,7,7,7,7] 26 | //输出:1 27 | // 28 | // 29 | // 30 | // 31 | // 提示: 32 | // 33 | // 34 | // 1 <= nums.length <= 2500 35 | // -10⁴ <= nums[i] <= 10⁴ 36 | // 37 | // 38 | // 39 | // 40 | // 进阶: 41 | // 42 | // 43 | // 你能将算法的时间复杂度降低到 O(n log(n)) 吗? 44 | // 45 | // Related Topics 数组 二分查找 动态规划 👍 2353 👎 0 46 | 47 | 48 | import java.util.Arrays; 49 | 50 | //leetcode submit region begin(Prohibit modification and deletion) 51 | class Solution { 52 | public int lengthOfLIS(int[] nums) { 53 | // 动态规划,状态转移方程式,max(maxLen[n],maxLen[j]),j 为 上一个小于 nums[n] 数的索引 54 | int[] maxLen = new int[nums.length]; 55 | Arrays.fill(maxLen, 1); 56 | int result = 1; 57 | for (int i = 1; i < nums.length; i++) { 58 | for (int j = i - 1; j >= 0; j--) { 59 | if (nums[i] > nums[j]) { 60 | maxLen[i] = Math.max(maxLen[i], maxLen[j] + 1); 61 | } 62 | } 63 | } 64 | for (int maxVal : maxLen) { 65 | result = Math.max(maxVal, result); 66 | } 67 | return result; 68 | } 69 | } 70 | //leetcode submit region end(Prohibit modification and deletion) 71 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[3]无重复字符的最长子串.java: -------------------------------------------------------------------------------- 1 | //给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 2 | // 3 | // 4 | // 5 | // 示例 1: 6 | // 7 | // 8 | //输入: s = "abcabcbb" 9 | //输出: 3 10 | //解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 11 | // 12 | // 13 | // 示例 2: 14 | // 15 | // 16 | //输入: s = "bbbbb" 17 | //输出: 1 18 | //解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 19 | // 20 | // 21 | // 示例 3: 22 | // 23 | // 24 | //输入: s = "pwwkew" 25 | //输出: 3 26 | //解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 27 | //  请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 28 | // 29 | // 30 | // 31 | // 32 | // 提示: 33 | // 34 | // 35 | // 0 <= s.length <= 5 * 10⁴ 36 | // s 由英文字母、数字、符号和空格组成 37 | // 38 | // Related Topics 哈希表 字符串 滑动窗口 👍 7107 👎 0 39 | 40 | 41 | import java.util.HashMap; 42 | import java.util.Map; 43 | 44 | //leetcode submit region begin(Prohibit modification and deletion) 45 | class Solution { 46 | public int lengthOfLongestSubstring(String s) { 47 | Map map = new HashMap<>(); 48 | int left = 0, right = 0, result = 0; 49 | for (Character c : s.toCharArray()) { 50 | right++; 51 | map.put(c, map.getOrDefault(c, 0) + 1); 52 | while (map.get(c) > 1) { 53 | Character cur = s.charAt(left); 54 | map.put(cur, map.get(cur) - 1); 55 | left++; 56 | } 57 | result = Math.max(result, right - left); 58 | } 59 | return result; 60 | 61 | } 62 | } 63 | //leetcode submit region end(Prohibit modification and deletion) 64 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[46]全排列.java: -------------------------------------------------------------------------------- 1 | //给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 2 | // 3 | // 4 | // 5 | // 示例 1: 6 | // 7 | // 8 | //输入:nums = [1,2,3] 9 | //输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 10 | // 11 | // 12 | // 示例 2: 13 | // 14 | // 15 | //输入:nums = [0,1] 16 | //输出:[[0,1],[1,0]] 17 | // 18 | // 19 | // 示例 3: 20 | // 21 | // 22 | //输入:nums = [1] 23 | //输出:[[1]] 24 | // 25 | // 26 | // 27 | // 28 | // 提示: 29 | // 30 | // 31 | // 1 <= nums.length <= 6 32 | // -10 <= nums[i] <= 10 33 | // nums 中的所有整数 互不相同 34 | // 35 | // Related Topics 数组 回溯 👍 1868 👎 0 36 | 37 | 38 | import java.util.ArrayList; 39 | import java.util.LinkedList; 40 | import java.util.List; 41 | 42 | //leetcode submit region begin(Prohibit modification and deletion) 43 | class Solution { 44 | private List> resultList; 45 | 46 | public List> permute(int[] nums) { 47 | resultList = new ArrayList<>(); 48 | traverse(new LinkedList<>(), nums); 49 | return resultList; 50 | } 51 | 52 | private void traverse(LinkedList result, int[] nums) { 53 | if (result.size() == nums.length) { 54 | resultList.add(new ArrayList<>(result)); 55 | return; 56 | } 57 | for (int i = 0; i < nums.length; i++) { 58 | if (result.contains(nums[i])) { 59 | continue; 60 | } 61 | result.add(nums[i]); 62 | traverse(result, nums); 63 | result.removeLast(); 64 | } 65 | } 66 | } 67 | //leetcode submit region end(Prohibit modification and deletion) 68 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[503]下一个更大元素 II.java: -------------------------------------------------------------------------------- 1 | //给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 2 | // 。 3 | // 4 | // 数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 5 | //。 6 | // 7 | // 8 | // 9 | // 示例 1: 10 | // 11 | // 12 | //输入: nums = [1,2,1] 13 | //输出: [2,-1,2] 14 | //解释: 第一个 1 的下一个更大的数是 2; 15 | //数字 2 找不到下一个更大的数; 16 | //第二个 1 的下一个最大的数需要循环搜索,结果也是 2。 17 | // 18 | // 19 | // 示例 2: 20 | // 21 | // 22 | //输入: nums = [1,2,3,4,3] 23 | //输出: [2,3,4,-1,4] 24 | // 25 | // 26 | // 27 | // 28 | // 提示: 29 | // 30 | // 31 | // 1 <= nums.length <= 10⁴ 32 | // -10⁹ <= nums[i] <= 10⁹ 33 | // 34 | // Related Topics 栈 数组 单调栈 👍 575 👎 0 35 | 36 | 37 | import java.util.Arrays; 38 | import java.util.HashMap; 39 | import java.util.Map; 40 | import java.util.Stack; 41 | 42 | //leetcode submit region begin(Prohibit modification and deletion) 43 | class Solution { 44 | public int[] nextGreaterElements(int[] nums) { 45 | Stack stack = new Stack<>(); 46 | int len = nums.length; 47 | int[] result = new int[len]; 48 | Arrays.fill(result, -1); 49 | // 计算 nums2 的下一更大元素 50 | for (int i = 0; i < len * 2 - 1; i++) { 51 | while (!stack.isEmpty() && nums[stack.peek()] < nums[i % len]) { 52 | result[stack.pop()] = nums[i % len]; 53 | } 54 | stack.push(i % len); 55 | } 56 | return result; 57 | } 58 | } 59 | //leetcode submit region end(Prohibit modification and deletion) 60 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[509]斐波那契数.java: -------------------------------------------------------------------------------- 1 | //斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: 2 | // 3 | // 4 | //F(0) = 0,F(1) = 1 5 | //F(n) = F(n - 1) + F(n - 2),其中 n > 1 6 | // 7 | // 8 | // 给定 n ,请计算 F(n) 。 9 | // 10 | // 11 | // 12 | // 示例 1: 13 | // 14 | // 15 | //输入:n = 2 16 | //输出:1 17 | //解释:F(2) = F(1) + F(0) = 1 + 0 = 1 18 | // 19 | // 20 | // 示例 2: 21 | // 22 | // 23 | //输入:n = 3 24 | //输出:2 25 | //解释:F(3) = F(2) + F(1) = 1 + 1 = 2 26 | // 27 | // 28 | // 示例 3: 29 | // 30 | // 31 | //输入:n = 4 32 | //输出:3 33 | //解释:F(4) = F(3) + F(2) = 2 + 1 = 3 34 | // 35 | // 36 | // 37 | // 38 | // 提示: 39 | // 40 | // 41 | // 0 <= n <= 30 42 | // 43 | // Related Topics 递归 记忆化搜索 数学 动态规划 👍 425 👎 0 44 | 45 | 46 | //leetcode submit region begin(Prohibit modification and deletion) 47 | class Solution { 48 | // public int fib(int n) { 49 | // // 自底向上 50 | // if (n == 0) { 51 | // return 0; 52 | // } 53 | // int n1 = 0, n2 = 1; 54 | // for (int i = 2; i <= n; i++) { 55 | // int temp = n2; 56 | // n2 = n1 + n2; 57 | // n1 = temp; 58 | // } 59 | // return n2; 60 | // } 61 | 62 | public int fib(int n) { 63 | // 自顶向下 64 | int[] memo = new int[n + 1]; 65 | return fn(n, memo); 66 | } 67 | 68 | private int fn(int n, int[] memo) { 69 | if (n == 0) { 70 | return 0; 71 | } 72 | if (n == 1||n==2) { 73 | return 1; 74 | } 75 | if (memo[n] != 0) { 76 | return memo[n]; 77 | } 78 | memo[n] = fn(n - 1, memo) + fn(n - 2, memo); 79 | return memo[n]; 80 | } 81 | } 82 | //leetcode submit region end(Prohibit modification and deletion) 83 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[53]最大子数组和.java: -------------------------------------------------------------------------------- 1 | //给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 2 | // 3 | // 子数组 是数组中的一个连续部分。 4 | // 5 | // 6 | // 7 | // 示例 1: 8 | // 9 | // 10 | //输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 11 | //输出:6 12 | //解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。 13 | // 14 | // 15 | // 示例 2: 16 | // 17 | // 18 | //输入:nums = [1] 19 | //输出:1 20 | // 21 | // 22 | // 示例 3: 23 | // 24 | // 25 | //输入:nums = [5,4,-1,7,8] 26 | //输出:23 27 | // 28 | // 29 | // 30 | // 31 | // 提示: 32 | // 33 | // 34 | // 1 <= nums.length <= 10⁵ 35 | // -10⁴ <= nums[i] <= 10⁴ 36 | // 37 | // 38 | // 39 | // 40 | // 进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。 41 | // Related Topics 数组 分治 动态规划 👍 4611 👎 0 42 | 43 | 44 | import static java.lang.Math.max; 45 | 46 | //leetcode submit region begin(Prohibit modification and deletion) 47 | class Solution { 48 | public int maxSubArray(int[] nums) { 49 | // 动态方程 sum[n]=max(nums[n],sum[n-1]) 50 | int[] sum = new int[nums.length]; 51 | sum[0] = nums[0]; 52 | for (int i = 1; i < nums.length; i++) { 53 | sum[i] = Math.max(nums[i], sum[i - 1] + nums[i]); 54 | } 55 | return sum[nums.length - 1]; 56 | } 57 | } 58 | //leetcode submit region end(Prohibit modification and deletion) 59 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[700]二叉搜索树中的搜索.java: -------------------------------------------------------------------------------- 1 | //给定二叉搜索树(BST)的根节点 root 和一个整数值 val。 2 | // 3 | // 你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。 4 | // 5 | // 6 | // 7 | // 示例 1: 8 | // 9 | // 10 | // 11 | // 12 | //输入:root = [4,2,7,1,3], val = 2 13 | //输出:[2,1,3] 14 | // 15 | // 16 | // Example 2: 17 | // 18 | // 19 | //输入:root = [4,2,7,1,3], val = 5 20 | //输出:[] 21 | // 22 | // 23 | // 24 | // 25 | // 提示: 26 | // 27 | // 28 | // 数中节点数在 [1, 5000] 范围内 29 | // 1 <= Node.val <= 10⁷ 30 | // root 是二叉搜索树 31 | // 1 <= val <= 10⁷ 32 | // 33 | // Related Topics 树 二叉搜索树 二叉树 👍 251 👎 0 34 | 35 | 36 | //leetcode submit region begin(Prohibit modification and deletion) 37 | 38 | import javax.swing.tree.TreeNode; 39 | 40 | /** 41 | * Definition for a binary tree node. 42 | * public class TreeNode { 43 | * int val; 44 | * TreeNode left; 45 | * TreeNode right; 46 | * TreeNode() {} 47 | * TreeNode(int val) { this.val = val; } 48 | * TreeNode(int val, TreeNode left, TreeNode right) { 49 | * this.val = val; 50 | * this.left = left; 51 | * this.right = right; 52 | * } 53 | * } 54 | */ 55 | class Solution { 56 | public TreeNode searchBST(TreeNode root, int val) { 57 | if (root == null) { 58 | return null; 59 | } 60 | if (root.val == val) { 61 | return root; 62 | } else if (root.val < val) { 63 | return searchBST(root.right, val); 64 | } else { 65 | return searchBST(root.left, val); 66 | } 67 | } 68 | } 69 | //leetcode submit region end(Prohibit modification and deletion) 70 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[701]二叉搜索树中的插入操作.java: -------------------------------------------------------------------------------- 1 | //给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原 2 | //始二叉搜索树中的任意节点值都不同。 3 | // 4 | // 注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。 5 | // 6 | // 7 | // 8 | // 示例 1: 9 | // 10 | // 11 | //输入:root = [4,2,7,1,3], val = 5 12 | //输出:[4,2,7,1,3,5] 13 | //解释:另一个满足题目要求可以通过的树是: 14 | // 15 | // 16 | // 17 | // 示例 2: 18 | // 19 | // 20 | //输入:root = [40,20,60,10,30,50,70], val = 25 21 | //输出:[40,20,60,10,30,50,70,null,null,25] 22 | // 23 | // 24 | // 示例 3: 25 | // 26 | // 27 | //输入:root = [4,2,7,1,3,null,null,null,null,null,null], val = 5 28 | //输出:[4,2,7,1,3,5] 29 | // 30 | // 31 | // 32 | // 33 | // 提示: 34 | // 35 | // 36 | // 树中的节点数将在 [0, 10⁴]的范围内。 37 | // -10⁸ <= Node.val <= 10⁸ 38 | // 所有值 Node.val 是 独一无二 的。 39 | // -10⁸ <= val <= 10⁸ 40 | // 保证 val 在原始BST中不存在。 41 | // 42 | // Related Topics 树 二叉搜索树 二叉树 👍 276 👎 0 43 | 44 | 45 | //leetcode submit region begin(Prohibit modification and deletion) 46 | 47 | import javax.swing.tree.TreeNode; 48 | 49 | /** 50 | * Definition for a binary tree node. 51 | * public class TreeNode { 52 | * int val; 53 | * TreeNode left; 54 | * TreeNode right; 55 | * TreeNode() {} 56 | * TreeNode(int val) { this.val = val; } 57 | * TreeNode(int val, TreeNode left, TreeNode right) { 58 | * this.val = val; 59 | * this.left = left; 60 | * this.right = right; 61 | * } 62 | * } 63 | */ 64 | class Solution { 65 | public TreeNode insertIntoBST(TreeNode root, int val) { 66 | if (root == null) { 67 | return new TreeNode(val); 68 | } 69 | if (root.val == val) { 70 | return root; 71 | } else if (root.val < val) { 72 | root.right = insertIntoBST(root.right, val); 73 | } else { 74 | root.left = insertIntoBST(root.left, val); 75 | } 76 | return root; 77 | } 78 | } 79 | //leetcode submit region end(Prohibit modification and deletion) 80 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[704]二分查找.java: -------------------------------------------------------------------------------- 1 | //给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否 2 | //则返回 -1。 3 | // 4 | // 5 | //示例 1: 6 | // 7 | // 输入: nums = [-1,0,3,5,9,12], target = 9 8 | //输出: 4 9 | //解释: 9 出现在 nums 中并且下标为 4 10 | // 11 | // 12 | // 示例 2: 13 | // 14 | // 输入: nums = [-1,0,3,5,9,12], target = 2 15 | //输出: -1 16 | //解释: 2 不存在 nums 中因此返回 -1 17 | // 18 | // 19 | // 20 | // 21 | // 提示: 22 | // 23 | // 24 | // 你可以假设 nums 中的所有元素是不重复的。 25 | // n 将在 [1, 10000]之间。 26 | // nums 的每个元素都将在 [-9999, 9999]之间。 27 | // 28 | // Related Topics 数组 二分查找 👍 702 👎 0 29 | 30 | 31 | //leetcode submit region begin(Prohibit modification and deletion) 32 | class Solution { 33 | public int search(int[] nums, int target) { 34 | if (nums == null || nums.length == 0) { 35 | return -1; 36 | } 37 | int left = 0, right = nums.length - 1; 38 | while (left <= right) { 39 | int mid = left + (right - left) / 2; 40 | if (nums[mid] == target) { 41 | return mid; 42 | } else if (nums[mid] < target) { 43 | left = mid + 1; 44 | } else if (nums[mid] > target) { 45 | right = mid - 1; 46 | } 47 | 48 | } 49 | return -1; 50 | } 51 | } 52 | //leetcode submit region end(Prohibit modification and deletion) 53 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[70]爬楼梯.java: -------------------------------------------------------------------------------- 1 | //假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 2 | // 3 | // 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 4 | // 5 | // 6 | // 7 | // 示例 1: 8 | // 9 | // 10 | //输入:n = 2 11 | //输出:2 12 | //解释:有两种方法可以爬到楼顶。 13 | //1. 1 阶 + 1 阶 14 | //2. 2 阶 15 | // 16 | // 示例 2: 17 | // 18 | // 19 | //输入:n = 3 20 | //输出:3 21 | //解释:有三种方法可以爬到楼顶。 22 | //1. 1 阶 + 1 阶 + 1 阶 23 | //2. 1 阶 + 2 阶 24 | //3. 2 阶 + 1 阶 25 | // 26 | // 27 | // 28 | // 29 | // 提示: 30 | // 31 | // 32 | // 1 <= n <= 45 33 | // 34 | // Related Topics 记忆化搜索 数学 动态规划 👍 2299 👎 0 35 | 36 | 37 | //leetcode submit region begin(Prohibit modification and deletion) 38 | class Solution { 39 | public int climbStairs(int n) { 40 | // 套壳的斐波那契额数列,自底向上 41 | if (n == 1) { 42 | return 1; 43 | } 44 | int n1 = 1, n2 = 2; 45 | for (int i = 3; i <= n; i++) { 46 | int temp = n2; 47 | n2 = n1 + n2; 48 | n1 = temp; 49 | } 50 | return n2; 51 | } 52 | } 53 | //leetcode submit region end(Prohibit modification and deletion) 54 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[739]每日温度.java: -------------------------------------------------------------------------------- 1 | //给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指在第 i 天之后,才会有更高的温度 2 | //。如果气温在这之后都不会升高,请在该位置用 0 来代替。 3 | // 4 | // 5 | // 6 | // 示例 1: 7 | // 8 | // 9 | //输入: temperatures = [73,74,75,71,69,72,76,73] 10 | //输出: [1,1,4,2,1,1,0,0] 11 | // 12 | // 13 | // 示例 2: 14 | // 15 | // 16 | //输入: temperatures = [30,40,50,60] 17 | //输出: [1,1,1,0] 18 | // 19 | // 20 | // 示例 3: 21 | // 22 | // 23 | //输入: temperatures = [30,60,90] 24 | //输出: [1,1,0] 25 | // 26 | // 27 | // 28 | // 提示: 29 | // 30 | // 31 | // 1 <= temperatures.length <= 10⁵ 32 | // 30 <= temperatures[i] <= 100 33 | // 34 | // Related Topics 栈 数组 单调栈 👍 1055 👎 0 35 | 36 | 37 | import java.util.HashMap; 38 | import java.util.Map; 39 | import java.util.Stack; 40 | 41 | //leetcode submit region begin(Prohibit modification and deletion) 42 | class Solution { 43 | public int[] dailyTemperatures(int[] temperatures) { 44 | // 单调栈 45 | Stack stack = new Stack<>(); 46 | int[] result = new int[temperatures.length]; 47 | for (int i = temperatures.length - 1; i >= 0; i--) { 48 | while (!stack.isEmpty() && temperatures[stack.peek()] <= temperatures[i]) { 49 | stack.pop(); 50 | } 51 | result[i] = stack.isEmpty() ? 0 : stack.peek()-i; 52 | // 存储索引值 53 | stack.push(i); 54 | } 55 | return result; 56 | } 57 | } 58 | //leetcode submit region end(Prohibit modification and deletion) 59 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[875]爱吃香蕉的珂珂.java: -------------------------------------------------------------------------------- 1 | //珂珂喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。 2 | // 3 | // 珂珂可以决定她吃香蕉的速度 K (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 K 根。如果这堆香蕉少于 K 根,她将吃掉这堆的所有香蕉,然后 4 | //这一小时内不会再吃更多的香蕉。 5 | // 6 | // 珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。 7 | // 8 | // 返回她可以在 H 小时内吃掉所有香蕉的最小速度 K(K 为整数)。 9 | // 10 | // 11 | // 12 | // 13 | // 14 | // 15 | // 示例 1: 16 | // 17 | // 输入: piles = [3,6,7,11], H = 8 18 | //输出: 4 19 | // 20 | // 21 | // 示例 2: 22 | // 23 | // 输入: piles = [30,11,23,4,20], H = 5 24 | //输出: 30 25 | // 26 | // 27 | // 示例 3: 28 | // 29 | // 输入: piles = [30,11,23,4,20], H = 6 30 | //输出: 23 31 | // 32 | // 33 | // 34 | // 35 | // 提示: 36 | // 37 | // 38 | // 1 <= piles.length <= 10^4 39 | // piles.length <= H <= 10^9 40 | // 1 <= piles[i] <= 10^9 41 | // 42 | // Related Topics 数组 二分查找 👍 266 👎 0 43 | 44 | 45 | //leetcode submit region begin(Prohibit modification and deletion) 46 | class Solution { 47 | public int minEatingSpeed(int[] piles, int h) { 48 | int left = 1; 49 | // 空间换时间,不遍历获取最大值,直接以最大取值为边界 50 | int right = 1000000000 + 1; 51 | while (left < right) { 52 | int mid = left + (right - left) / 2; 53 | if (fun(piles, mid) <= h) { 54 | right = mid; 55 | } else { 56 | left = mid + 1; 57 | } 58 | } 59 | return left; 60 | } 61 | 62 | private int fun(int[] piles, int x) { 63 | int hours = 0; 64 | for (int i = 0; i < piles.length; i++) { 65 | hours += piles[i] / x; 66 | if (piles[i] % x > 0) { 67 | hours++; 68 | } 69 | } 70 | return hours; 71 | } 72 | } 73 | //leetcode submit region end(Prohibit modification and deletion) 74 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[876]链表的中间结点.java: -------------------------------------------------------------------------------- 1 | //给定一个头结点为 head 的非空单链表,返回链表的中间结点。 2 | // 3 | // 如果有两个中间结点,则返回第二个中间结点。 4 | // 5 | // 6 | // 7 | // 示例 1: 8 | // 9 | // 10 | //输入:[1,2,3,4,5] 11 | //输出:此列表中的结点 3 (序列化形式:[3,4,5]) 12 | //返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。 13 | //注意,我们返回了一个 ListNode 类型的对象 ans,这样: 14 | //ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = 15 | //NULL. 16 | // 17 | // 18 | // 示例 2: 19 | // 20 | // 21 | //输入:[1,2,3,4,5,6] 22 | //输出:此列表中的结点 4 (序列化形式:[4,5,6]) 23 | //由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。 24 | // 25 | // 26 | // 27 | // 28 | // 提示: 29 | // 30 | // 31 | // 给定链表的结点数介于 1 和 100 之间。 32 | // 33 | // Related Topics 链表 双指针 👍 506 👎 0 34 | 35 | 36 | //leetcode submit region begin(Prohibit modification and deletion) 37 | /** 38 | * Definition for singly-linked list. 39 | * public class ListNode { 40 | * int val; 41 | * ListNode next; 42 | * ListNode() {} 43 | * ListNode(int val) { this.val = val; } 44 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 45 | * } 46 | */ 47 | class Solution { 48 | public ListNode middleNode(ListNode head) { 49 | ListNode fast = head, slow = head; 50 | while(fast != null && fast.next != null){ 51 | slow = slow.next; 52 | fast = fast.next.next; 53 | } 54 | return slow; 55 | } 56 | } 57 | //leetcode submit region end(Prohibit modification and deletion) 58 | -------------------------------------------------------------------------------- /leetcode/editor/cn/[98]验证二叉搜索树.java: -------------------------------------------------------------------------------- 1 | //给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。 2 | // 3 | // 有效 二叉搜索树定义如下: 4 | // 5 | // 6 | // 节点的左子树只包含 小于 当前节点的数。 7 | // 节点的右子树只包含 大于 当前节点的数。 8 | // 所有左子树和右子树自身必须也是二叉搜索树。 9 | // 10 | // 11 | // 12 | // 13 | // 示例 1: 14 | // 15 | // 16 | //输入:root = [2,1,3] 17 | //输出:true 18 | // 19 | // 20 | // 示例 2: 21 | // 22 | // 23 | //输入:root = [5,1,4,null,null,3,6] 24 | //输出:false 25 | //解释:根节点的值是 5 ,但是右子节点的值是 4 。 26 | // 27 | // 28 | // 29 | // 30 | // 提示: 31 | // 32 | // 33 | // 树中节点数目范围在[1, 10⁴] 内 34 | // -2³¹ <= Node.val <= 2³¹ - 1 35 | // 36 | // Related Topics 树 深度优先搜索 二叉搜索树 二叉树 👍 1465 👎 0 37 | 38 | 39 | //leetcode submit region begin(Prohibit modification and deletion) 40 | 41 | import javax.swing.tree.TreeNode; 42 | 43 | /** 44 | * Definition for a binary tree node. 45 | * public class TreeNode { 46 | * int val; 47 | * TreeNode left; 48 | * TreeNode right; 49 | * TreeNode() {} 50 | * TreeNode(int val) { this.val = val; } 51 | * TreeNode(int val, TreeNode left, TreeNode right) { 52 | * this.val = val; 53 | * this.left = left; 54 | * this.right = right; 55 | * } 56 | * } 57 | */ 58 | class Solution { 59 | public boolean isValidBST(TreeNode root) { 60 | boolean result = isValidBST(root, null, null); 61 | return result; 62 | } 63 | 64 | private boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) { 65 | if (root == null) { 66 | return true; 67 | } 68 | if (min != null && root.val <= min.val) { 69 | return false; 70 | } 71 | if (max != null && root.val >= max.val) { 72 | return false; 73 | } 74 | return isValidBST(root.left, min, root) && isValidBST(root.right, root, max); 75 | } 76 | } 77 | //leetcode submit region end(Prohibit modification and deletion) 78 | -------------------------------------------------------------------------------- /out/production/LeetCode/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea/LeetCode.iml 3 | .idea/leetcode/editor.xml 4 | .idea/misc.xml 5 | .idea/modules.xml 6 | .idea/vcs.xml 7 | /out/ 8 | /leetcode/editor/cn/doc/content/ 9 | -------------------------------------------------------------------------------- /out/production/LeetCode/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | --------------------------------------------------------------------------------