├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── LICENSE ├── LeetCode ├── 1-两数之和 │ ├── leetcode1.cpp │ └── twoSum.py ├── 1143-最长公共子序列 │ └── leet1143.cpp ├── 121-买卖股票的最佳时机 │ ├── 121-maxProfit.py │ ├── 122-maxProfit2.py │ ├── 123-maxProfit3.py │ ├── FSM.jpg │ ├── main121.cpp │ ├── main122.cpp │ └── main123.cpp ├── 125-验证回文串 │ ├── isPalindrome.py │ └── main125.cpp ├── 136-出现一次的数字 │ ├── main136.cpp │ └── singleNumber.py ├── 14-最长公共前缀 │ └── leetcode14.cpp ├── 147-对链表进行插入排序 │ └── leetcode147.cpp ├── 15-三数之和 │ ├── leetcode15.cpp │ └── treeSum.py ├── 152-连续子数组的最大积 │ └── leetcode152.cpp ├── 162-寻找峰值 │ └── leetcode162.cpp ├── 167-两数之和2-输入有序数组 │ └── twoSum.py ├── 189-旋转数组 │ ├── main189.cpp │ └── rotate.py ├── 198-打家劫舍 │ ├── leetcode198.cpp │ └── rob.py ├── 2-两数相加 │ ├── addTwoNumbers.py │ └── main2.cpp ├── 200-岛屿数量 │ ├── leetcode200.cpp │ └── numIslands.py ├── 217-存在重复元素 │ ├── duplicate.py │ └── main217.cpp ├── 234-回文链表 │ └── leetcode234.cpp ├── 26-删除排序数组中的重复项 │ ├── main26.cpp │ └── remove.py ├── 268-缺失数字 │ └── leetcode268.cpp ├── 28-实现strStr() │ ├── main28.cpp │ └── strStr.py ├── 283-移动零 │ └── moveZeros.py ├── 3-无重复字符的最长字串 │ └── leetcode3.cpp ├── 300-最长上升子序列 │ └── leetcode300.cpp ├── 322-零钱兑换 │ ├── coinChange.py │ └── leetcode322.cpp ├── 324-摆动排序2 │ ├── main324.cpp │ └── wiggle-sort-ii.py ├── 334-递增的三元子序列 │ └── leetcode334.cpp ├── 349-两个数组的交集 │ ├── 349-interSection.py │ └── 350-interSection2.py ├── 35-搜索插入位置 │ ├── main35.cpp │ └── searchInsert.py ├── 367-有效的完全平方数 │ └── isPerfectSquare.py ├── 374-猜数字大小 │ └── guessNumber.py ├── 387-字符串中的第一个唯一字符 │ ├── leetcode387.cpp │ └── leetcode387.py ├── 392-判断子序列 │ ├── leetcode392.cpp │ └── leetcode392.py ├── 406-根据身高重建队列 │ └── leetcode406.cpp ├── 416-分割等和子集 │ ├── canPartition.py │ └── leetcode416.cpp ├── 461-汉明距离 │ └── leetcode461.cpp ├── 474-一和零 │ ├── leetcode474.cpp │ └── oneAndZero.py ├── 48-旋转图像 │ ├── method.jpg │ └── rotate.py ├── 494-目标和 │ ├── findTargetSumWays.py │ └── leetcode494.cpp ├── 5-最长回文子串 │ ├── longestPalindrome.py │ └── mian5.cpp ├── 516-最长回文子序列 │ └── leetcode516.cpp ├── 547-朋友圈 │ └── friend.py ├── 55-跳跃游戏 │ ├── jump.py │ └── leetcode55.cpp ├── 62-不同路径 │ ├── leetcode62.cpp │ └── uniquePaths.py ├── 64-最小路径和 │ ├── leetcode64.cpp │ └── minPathSum.py ├── 65-有效数字 │ ├── FSM.png │ └── isNumber.py ├── 66-加一 │ ├── main66.cpp │ └── plusOne.py ├── 69-x的平方根 │ └── mySqrt.py ├── 75-颜色排序 │ ├── main75.cpp │ └── sortColors.py ├── 876-链表的中间结点 │ ├── leetcode876.cpp │ └── leetcode876.py └── 97-交错字符串 │ └── isInterleave.py ├── LintCode ├── 1-01背包无价值 │ ├── backPack.py │ └── lintcode92.cpp ├── 2-01背包有价值 │ ├── backPack2.py │ └── lintcode125.cpp ├── 3-完全背包 │ ├── backPage.py │ └── lintcode-x.cpp ├── 4-01背包返回方案数 │ ├── backPage.py │ └── lintcode-x.cpp └── 5-完全背包返回方案数 │ ├── backPage.py │ └── lintcode562.cpp ├── README.md ├── README1.md ├── acmcoder ├── 1-约德尔测试 │ └── yueDeErCeShi.py └── 2-格子游戏 │ └── geZiYouXi.py ├── dataStructure ├── README.md ├── assets │ └── README │ │ ├── 20200423161856.png │ │ ├── 953680-20171102225031732-905731989.png │ │ ├── 953680-20171102225105091-760301993.png │ │ ├── 953680-20171102225137216-1323160728.png │ │ ├── 953680-20171102225214701-1271434709.png │ │ ├── 953680-20171102225258170-1980199509.png │ │ ├── AVL_RL1.png │ │ ├── AVL_RL2-1646061568338.png │ │ ├── AVL_RL2.png │ │ ├── v2-05246384c1c16537ca6176983bdb2627_b.webp │ │ ├── v2-2ddb0f9b832fff594e294dffc299b373_b.webp │ │ ├── v2-373766641d1c03a78f3d7eac803d1f57_b.webp │ │ ├── v2-37639b80cb65b60a531d3f5dc73dad52_720w.jpg │ │ ├── v2-41a3bdcb0c8b6478446c09ce22d14561_720w.jpg │ │ ├── v2-db1cdb0da952a71f9b6d64b2608467eb_b.webp │ │ ├── v2-e60c01fa31634d9c63c63ecfb58036b2_720w.jpg │ │ ├── v2-e7044e4965ba640ee9ef35beac407cdc_b-1646060200511.webp │ │ ├── v2-e7044e4965ba640ee9ef35beac407cdc_b.jpg │ │ ├── v2-e7044e4965ba640ee9ef35beac407cdc_b.webp │ │ ├── v2-f8e97ce8bff6af406ca2e3399be7ad5e_720w.jpg │ │ ├── v2-f95f74ae3e76458d56ae3208bdde5987_720w.jpg │ │ └── v2-fd82c10388b933d1c09d1fbe297984ef_720w.jpg ├── list │ ├── doubleLinkedList.cpp │ ├── doubleLinkedList.py │ ├── linkedList.cpp │ └── linkedList.py ├── queue │ ├── deque.py │ ├── loopqueue.py │ ├── queue.cpp │ ├── queue.jpg │ └── queue.py ├── sort.cpp ├── sort │ ├── bubble.cpp │ ├── bubbleSort.py │ ├── insert.cpp │ ├── insertSort.py │ ├── makefile │ ├── merge.cpp │ ├── mergeSort.py │ ├── mysort.h │ ├── quick.cpp │ ├── quickSort.py │ ├── radixSort.py │ ├── select.cpp │ ├── selectSort.py │ ├── shell.cpp │ ├── shellSort.py │ └── sort.cpp ├── stack │ ├── stack.cpp │ └── stack.py └── tree │ ├── BST.cpp │ └── BinaryTree.py ├── exercise └── printThreadABC.cpp ├── framework ├── log.hpp ├── safeMessageQueue │ ├── Dvr.cpp │ ├── Dvr.hpp │ ├── Hdd.cpp │ ├── Hdd.hpp │ ├── Makefile │ ├── ModuleManager.cpp │ ├── ModuleManager.hpp │ ├── garbo.hpp │ ├── main.cpp │ ├── message.hpp │ ├── observe.cpp │ ├── observer.hpp │ ├── safequeue.hpp │ ├── subject.cpp │ └── subject.hpp └── safeRingBuffer │ ├── Makefile │ ├── RingBuffer.cpp │ ├── RingBuffer.hpp │ └── main.cpp ├── function ├── int2str.cpp ├── memcpy.cpp ├── str2int.cpp ├── strcat.cpp ├── strcmp.cpp ├── strcpy.cpp ├── strlen.cpp ├── strstr.cpp ├── swapInt.cpp └── swapStr.cpp ├── io ├── newcode.cpp └── newcode.py ├── itcoder ├── 1-电话号码分身_小米2017 │ └── telphone.py ├── 2-小米大礼包_小米2019 │ └── bigBag.py ├── acm.py ├── hw1.py ├── hw2.py └── qax.py ├── sources ├── 1x.svg ├── 2.svg ├── 2x.svg ├── all.svg ├── bfs.svg ├── c.svg ├── coding.svg ├── dfs.svg ├── dp.svg ├── fsm.svg ├── g.svg ├── graph.svg ├── hash.svg ├── heap.svg ├── list.svg ├── py.svg ├── q.svg ├── readme.md ├── search.svg ├── sort.svg ├── stack.svg ├── str.svg ├── tree.svg └── union.svg ├── usefulLink └── coding.md └── 剑指offer ├── 10-fibonacci数列 ├── fibonacci.py ├── jumpFloor.cpp ├── jumpFloor.py ├── jumpFloor2.cpp ├── jumpFloor2.py └── rectCover.py ├── 11-旋转数组的最小数字 ├── JZ11.cpp └── minOfRotatingArray.py ├── 12-矩阵中的路径 ├── 12 hasPath.py └── JZ12.cpp ├── 13-机器人的运动范围 ├── JZ13.cpp └── movingCount.py ├── 14-剪绳子 ├── JZ14.cpp └── maxCut.py ├── 15-二进制中1的个数 ├── JZ15.cpp └── numberOf1.py ├── 16-数值的整数次方 ├── JZ16.cpp └── Power.py ├── 18-删除链表的节点 ├── deleteNode.py ├── deleteduplication.py ├── mainJZ18-2.cpp └── mainJZ18.cpp ├── 19-正则表达式匹配 ├── JZ19.cpp └── match.py ├── 20-表示数值的字符串 └── isNumeric.py ├── 21-调整数组顺序使奇数位于偶数前面 ├── JZ21.cpp └── reOrderArray.py ├── 22-链表中倒数第k个节点 ├── JZ22.cpp └── findKthToTail.py ├── 23-链表中环的入口节点 ├── JZ23.cpp └── entryNodeOfLoop.py ├── 24-反转链表 ├── JZ24.cpp └── reverseList.py ├── 25-合并两个排序的链表 ├── JZ25.cpp └── merge.py ├── 26-树的子结构 ├── JZ26.cpp └── hasSubTree.py ├── 27-二叉树的镜像 ├── JZ27.cpp └── mirror.py ├── 28-对称二叉树 ├── JZ28.cpp └── isSymmetrical.py ├── 29-顺时针打印矩阵 └── printMatrixClockWisely.py ├── 3-数组中重复的数字 ├── JZ3.cpp ├── duplication.py └── duplication2.py ├── 30-包含min函数的栈 ├── JZ30.cpp └── min.py ├── 31-栈的压入弹出序列 ├── JZ31.cpp └── isPopOrder.py ├── 32-从上到下打印二叉树 ├── JZ32-2.cpp ├── JZ32-3.cpp ├── JZ32.cpp ├── printFormTopToBottom.py ├── printManyLines.py └── printZHI.py ├── 33-二叉搜索树的后序遍历 └── verifySquenceOfBST.py ├── 34-二叉树中和为某一值的路径 ├── JZ34.cpp └── findPath.py ├── 36二叉搜索树与双向链表 └── convert.py ├── 38-字符串的排列 ├── Permutation.py ├── mainJZ36.cpp └── pailie.py ├── 39-数组中出现数字超过一半的数字 └── MoreThanHalfNum_Solution.py ├── 4-二维数组中的查找 ├── JZ4.cpp └── find.py ├── 40-最小的k个数 └── GetLeastNumbers_Solution.py ├── 42-连续子数组的最大和 ├── FindGreatestSumOfSubArray.py └── JZ42.cpp ├── 45-把数组排成最小的数 └── PrintMinNumber.py ├── 49-丑数 ├── ugly.cpp └── ugly.py ├── 5-替换空格 └── replaceBlank.py ├── 52-两个链表的第一个公共结点 ├── JZ52.cpp └── JZ52.py ├── 54-二叉搜索树的第k大节点 └── JZ54.py ├── 55-二叉树的深度 └── JZ55.py ├── 58-反转单词顺序 ├── JZ58-2.py └── JZ58.py ├── 6-反向打印链表 ├── 6 printListFromTailToHead.py └── mainJZ6.cpp ├── 7-重建二叉树 ├── JZ7.cpp └── reConstructBinaryTree.py ├── 8-二叉树的下一个节点 ├── getNext.py └── 详细解析.PNG ├── 9-用两个栈实现队列 ├── JZ9.cpp └── stack2queue.py └── linkedList.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | r 3 | s 4 | t 5 | test 6 | 7 | # temp 8 | AVL.cpp 9 | 10 | push.sh 11 | .idea/* 12 | data/* 13 | **/*.o 14 | */*.i 15 | */*.s 16 | **/__pycache__/* 17 | **/.vs/* 18 | .*/.vscode/* 19 | .vscode 20 | **/ConsoleApplication1/* 21 | *.out 22 | C++ 23 | 24 | t/* 25 | r/* 26 | test/* 27 | doing/* 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jinbo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LeetCode/1-两数之和/leetcode1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | https://leetcode-cn.com/problems/two-sum 3 | 4 | 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。 5 | 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 6 | 7 | 示例: 8 | 给定 nums = [2, 7, 11, 15], target = 9 9 | 10 | 因为 nums[0] + nums[1] = 2 + 7 = 9 11 | 所以返回 [0, 1] 12 | */ 13 | class Solution { 14 | public: 15 | vector twoSum(vector& nums, int target) { 16 | int size = nums.size(); 17 | map index; 18 | vector id(2); 19 | for (int i = 0; i < size; ++i) 20 | { 21 | index[nums[i]] = i; 22 | } 23 | for (int i = 0; i < size; ++i) 24 | { 25 | if (index.count(target - nums[i]) && index[target - nums[i]] != i) 26 | { 27 | id[0] = i; 28 | id[1] = index[target - nums[i]]; 29 | return id; 30 | } 31 | } 32 | return id; 33 | } 34 | }; -------------------------------------------------------------------------------- /LeetCode/1-两数之和/twoSum.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/two-sum 3 | 4 | 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 5 | 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 6 | 7 | 示例: 8 | 给定 nums = [2, 7, 11, 15], target = 9 9 | 10 | 因为 nums[0] + nums[1] = 2 + 7 = 9 11 | 所以返回 [0, 1] 12 | """ 13 | from typing import List 14 | 15 | 16 | class Solution: 17 | def twoSum(self, nums: List[int], target: int) -> List[int]: 18 | d = {} 19 | # 如果 nums = [3, 3], 那么 d = {3: 1} 只有一个值 20 | for value, key in enumerate(nums): 21 | d[key] = value 22 | 23 | for i, key in enumerate(nums): 24 | # 如果 nums = [3, 3], target = 6 25 | # 此时 i = 0, d[3] = 1 不等于 0,仍旧打印 [0, 1] 26 | if (target - key) in d.keys() and d[target - key] != i: 27 | return [i, d[target - key]] -------------------------------------------------------------------------------- /LeetCode/121-买卖股票的最佳时机/121-maxProfit.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock 4 | 5 | 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 6 | 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 7 | 注意你不能在买入股票前卖出股票。 8 | 9 | 示例 1: 10 | 输入: [7,1,5,3,6,4] 11 | 输出: 5 12 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 13 | 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 14 | 15 | 示例 2: 16 | 输入: [7,6,4,3,1] 17 | 输出: 0 18 | 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 19 | 20 | """ 21 | from typing import List 22 | 23 | 24 | class Solution: 25 | def maxProfit(self, prices: List[int]) -> int: 26 | """ 27 | 提示:动态规划 28 | 令 dp[i] 为从第零天到第 i 天(索引 i)的最大获利,并记录从第零天到第 i 天的股票最低价格 min_prices。 29 | 则状态转移方程为: 30 | dp[i] = max(dp[i-1], prices[i] - min_prices) 31 | 32 | """ 33 | if not prices: 34 | return 0 35 | dp = [0] * len(prices) 36 | min_prices = prices[0] 37 | for i in range(len(prices)): 38 | dp[i] = max(dp[i-1], prices[i] - min_prices) 39 | min_prices = min(prices[i], min_prices) 40 | return dp[-1] 41 | 42 | 43 | if __name__ == "__main__": 44 | f = Solution() 45 | prices = [7, 1, 5, 3, 6, 4] 46 | print(f.maxProfit(prices)) 47 | -------------------------------------------------------------------------------- /LeetCode/121-买卖股票的最佳时机/122-maxProfit2.py: -------------------------------------------------------------------------------- 1 | """ 2 | 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 3 | 4 | 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 5 | 6 | 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 7 | 8 | 示例 1: 9 | 10 | 输入: [7,1,5,3,6,4] 11 | 输出: 7 12 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 13 | 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 14 | """ 15 | from typing import List 16 | 17 | 18 | class Solution: 19 | def maxProfit(self, prices: List[int]) -> int: 20 | """ 21 | 提示: 22 | 做短期,能赚的就赚:比较相邻两日,若有增长,就前一日买后一日卖 23 | """ 24 | if len(prices) < 2: 25 | return 0 26 | increase = 0 27 | profit = 0 28 | for i in range(len(prices) - 1): 29 | increase = prices[i + 1] - prices[i] 30 | if increase > 0: 31 | profit += increase 32 | return profit 33 | -------------------------------------------------------------------------------- /LeetCode/121-买卖股票的最佳时机/123-maxProfit3.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii 4 | 5 | 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 6 | 设计一个算法来计算你所能获取的最大利润。你最多可以完成两笔交易。 7 | 注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 8 | 9 | 示例 1: 10 | 输入: [3,3,5,0,0,3,1,4] 11 | 输出: 6 12 | 解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 13 | 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。 14 | 15 | 示例 2: 16 | 输入: [1,2,3,4,5] 17 | 输出: 4 18 | 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 19 | 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 20 | 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 21 | 22 | 示例 3: 23 | 输入: [7,6,4,3,1] 24 | 输出: 0 25 | 解释: 在这个情况下, 没有交易完成, 所以最大利润为 0。 26 | 27 | """ 28 | 29 | 30 | class Solution: 31 | def maxProfit(self, prices: list) -> int: 32 | """ 33 | 提示:有限状态机 34 | 状态转移图见同目录下 FSM.png 35 | 36 | s0代表初始状态,初始时钱是 0。 37 | s1代表第一次买入后当前的钱, 38 | s2代表第一次卖出后当前的钱, 39 | s3代表第二次买入后当前的钱, 40 | s4代表第二次卖出后当前的钱。 41 | 42 | """ 43 | if not prices: 44 | return 0 45 | # s0 为未做任何操作时持有的本金,最终是比较本金加收益的值, 46 | # s0 可以设置为任意数,设置为 0,那么最终值就是收益。 47 | s0 = 0 48 | s1 = float('-inf') 49 | s2 = 0 50 | s3 = float('-inf') 51 | s4 = 0 52 | 53 | for price in prices: 54 | s1 = max(s1, s0 - price) 55 | s2 = max(s2, s1 + price) 56 | s3 = max(s3, s2 - price) 57 | s4 = max(s4, s3 + price) 58 | return s4 - s0 59 | 60 | -------------------------------------------------------------------------------- /LeetCode/121-买卖股票的最佳时机/FSM.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/LeetCode/121-买卖股票的最佳时机/FSM.jpg -------------------------------------------------------------------------------- /LeetCode/121-买卖股票的最佳时机/main122.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 3 | 4 | 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 5 | 6 | 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 7 | 8 | 示例 1: 9 | 10 | 输入: [7,1,5,3,6,4] 11 | 输出: 7 12 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 13 | 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 14 | 15 | */ 16 | 17 | 18 | class Solution { 19 | public: 20 | int maxProfit(vector& prices) { 21 | // 计算每两天的差价,能赚的就赚。 22 | if (prices.size() < 2) 23 | return 0; 24 | int increase = 0; 25 | int profit = 0; 26 | for (int i = 0; i < prices.size() - 1; ++i) 27 | { 28 | increase = prices[i + 1] - prices[i]; 29 | if (increase > 0) 30 | profit += increase; 31 | } 32 | return profit; 33 | } 34 | }; -------------------------------------------------------------------------------- /LeetCode/121-买卖股票的最佳时机/main123.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 3 | 设计一个算法来计算你所能获取的最大利润。你最多可以完成两笔交易。 4 | 注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 5 | 6 | 示例 1: 7 | 输入: [3,3,5,0,0,3,1,4] 8 | 输出: 6 9 | 解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 10 | 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。 11 | 12 | 示例 2: 13 | 输入: [1,2,3,4,5] 14 | 输出: 4 15 | 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 16 | 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 17 | 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 18 | 19 | 示例 3: 20 | 输入: [7,6,4,3,1] 21 | 输出: 0 22 | 解释: 在这个情况下, 没有交易完成, 所以最大利润为 0。 23 | */ 24 | 25 | class Solution { 26 | public: 27 | int maxProfit(vector& prices) { 28 | if(prices.empty()) 29 | return 0; 30 | //进行初始化,第一天 s1 将股票买入,其他状态全部初始化为最小值 31 | int s0 = 0; 32 | int s1 = INT_MIN; 33 | int s2= 0; 34 | int s3 = INT_MIN; 35 | int s4 = 0; 36 | 37 | for(int i = 0; i < prices.size(); ++i) 38 | { 39 | s1 = max(s1, s0 - prices[i]); //买入价格更低的股 40 | s2 = max(s2, s1 + prices[i]); //卖出当前股,或者不操作 41 | s3 = max(s3, s2 - prices[i]); //第二次买入,或者不操作 42 | s4 = max(s4, s3 + prices[i]); //第二次卖出,或者不操作 43 | } 44 | return s4 - s0; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /LeetCode/125-验证回文串/isPalindrome.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/valid-palindrome 4 | 5 | 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 6 | 说明:本题中,我们将空字符串定义为有效的回文串。 7 | 8 | 示例 1: 9 | 输入: "A man, a plan, a canal: Panama" 10 | 输出: true 11 | 12 | 示例 2: 13 | 输入: "race a car" 14 | 输出: false 15 | 16 | """ 17 | 18 | 19 | class Solution: 20 | def isPalindrome(self, s: str) -> bool: 21 | """ 22 | 提示: 23 | 令双指针分别指向字符串的首尾,然后从两边向中间逼近。 24 | 如果遇到数字和字符就判断双指针指向的字符是否相等,否则指针向中间逼近,直到双指针相遇。 25 | 26 | """ 27 | left = 0 28 | right = len(s) - 1 29 | while right > left: 30 | while right > left and not s[right].isalnum(): 31 | right -= 1 32 | while right > left and not s[left].isalnum(): 33 | left += 1 34 | if s[right].lower() == s[left].lower(): 35 | right -= 1 36 | left += 1 37 | else: 38 | return False 39 | return True -------------------------------------------------------------------------------- /LeetCode/125-验证回文串/main125.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isPalindrome(string s) { 4 | if (!s.size()) 5 | return true; 6 | int p1 = 0; 7 | int p2 = s.size() - 1; 8 | while (p1 < p2) 9 | { 10 | while (p1 < p2 && !isAlphaAndDigit(s[p1])) 11 | p1++; 12 | while (p1 < p2 && !isAlphaAndDigit(s[p2])) 13 | p2--; 14 | //cout << p1 << ' ' << p2 << endl; 15 | //cout << lower(s[p1]) << ' ' << lower(s[p2]) << endl; 16 | if (p1 > p2 or lower(s[p1]) != lower(s[p2])) 17 | return false; 18 | p1++; 19 | p2--; 20 | } 21 | return true; 22 | } 23 | 24 | bool isAlphaAndDigit(char ch) 25 | { 26 | if ((ch >= 'A' && ch <= 'Z') || 27 | (ch >= 'a' && ch <= 'z') || 28 | (ch >= '0' && ch <= '9')) 29 | return true; 30 | return false; 31 | } 32 | 33 | char lower(char ch) 34 | { 35 | if (ch >= 'A' && ch <= 'Z') 36 | return ch - 'A' + 'a'; 37 | return ch; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /LeetCode/136-出现一次的数字/main136.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include 3 | #include 4 | using namespace std; 5 | 6 | class Solution { 7 | public: 8 | int singleNumber(vector& nums) { 9 | int result = 0; 10 | for (int i = 0; i < nums.size(); ++i) { 11 | result ^= nums[i]; 12 | } 13 | return result; 14 | } 15 | }; 16 | 17 | int main() 18 | { 19 | Solution method; 20 | int arr[10] = {1, 2, 2, 4, 6, 1, 5, 4, 6, 0}; 21 | vector vec(arr, arr + 10); 22 | std::cout << method.singleNumber(vec); 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /LeetCode/136-出现一次的数字/singleNumber.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/single-number 3 | 4 | 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 5 | 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 6 | 7 | 示例 1: 8 | 输入: [2,2,1] 9 | 输出: 1 10 | 11 | 示例 2: 12 | 输入: [4,1,2,1,2] 13 | 输出: 4 14 | 15 | """ 16 | from typing import List 17 | 18 | 19 | class Solution: 20 | def singleNumber(self, nums: List[int]) -> int: 21 | """ 22 | 提示: 23 | 偶数个数自身异或就会等于0,0跟任何数异或等于该数字本身 24 | """ 25 | result = 0 26 | for x in nums: 27 | result ^= x 28 | return result -------------------------------------------------------------------------------- /LeetCode/14-最长公共前缀/leetcode14.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | /* 8 | 编写一个函数来查找字符串数组中的最长公共前缀。 9 | 如果不存在公共前缀,返回空字符串 ""。 10 | 11 | 示例 1: 12 | 输入: ["flower","flow","flight"] 13 | 输出: "fl" 14 | 15 | 示例 2: 16 | 输入: ["dog","racecar","car"] 17 | 输出: "" 18 | 解释: 输入不存在公共前缀。 19 | 20 | 说明: 21 | 所有输入只包含小写字母 a-z 。 22 | 23 | 来源:力扣(LeetCode) 24 | 链接:https://leetcode-cn.com/problems/longest-common-prefix 25 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 26 | */ 27 | 28 | 29 | class Solution { 30 | public: 31 | string longestCommonPrefix(vector& strs) { 32 | /* 33 | 方法一: 34 | 将第一个字符串设为最长公共前缀 res,之后从第二个字符串 strs[1] 开始, 35 | 逐个与 res 两两比较找出最长公共前缀,再用新的公共前缀更新 res 值。 36 | */ 37 | if (strs.empty()) 38 | return ""; 39 | 40 | string res = strs[0]; 41 | for (int i = 1; i < strs.size(); ++i) 42 | { 43 | if (res == "") 44 | break; 45 | res = common(res, strs[i]); 46 | } 47 | return res; 48 | } 49 | 50 | string common(string s1, string s2) 51 | { 52 | if (s1.empty() || s2.empty()) 53 | return ""; 54 | int length = s1.size() > s2.size() ? s2.size() : s1.size(); 55 | int i = 0; 56 | for (; i < length; ++i) 57 | { 58 | if (s1[i] != s2[i]) 59 | break; 60 | } 61 | string tmp(s1.begin(), s1.begin() + i); 62 | return tmp; 63 | } 64 | 65 | /* 66 | 方法二: 67 | 逐位比较 68 | */ 69 | }; 70 | 71 | 72 | -------------------------------------------------------------------------------- /LeetCode/147-对链表进行插入排序/leetcode147.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 对链表进行插入排序 3 | */ 4 | 5 | /** 6 | * Definition for singly-linked list. 7 | * struct ListNode { 8 | * int val; 9 | * ListNode *next; 10 | * ListNode(int x) : val(x), next(NULL) {} 11 | * }; 12 | */ 13 | class Solution 14 | { 15 | public: 16 | /** 17 | * 提示: 18 | * 使用递归,假设当前节点后面的节点都是有序, 19 | * 则只需要把当前节点插入到后面有序的节点的合适位置。 20 | */ 21 | ListNode *insertionSortList(ListNode *head) 22 | { 23 | if (head == nullptr) 24 | return nullptr; 25 | ListNode *p1 = head; 26 | ListNode *p2 = insertionSortList(head->next); 27 | if (p2 == nullptr || p1->val <= p2->val) 28 | { 29 | p1->next = p2; 30 | return p1; 31 | } 32 | ListNode *prev = p2; 33 | ListNode *curr = p2->next; 34 | while (curr != nullptr && curr->val < p1->val) 35 | { 36 | prev = curr; 37 | curr = curr->next; 38 | } 39 | prev->next = p1; 40 | p1->next = curr; 41 | return p2; 42 | } 43 | }; -------------------------------------------------------------------------------- /LeetCode/152-连续子数组的最大积/leetcode152.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | https://leetcode-cn.com/problems/maximum-product-subarray 3 | 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。 4 | 5 | 示例 1: 6 | 输入: [2,3,-2,4] 7 | 输出: 6 8 | 解释: 子数组 [2,3] 有最大乘积 6。 9 | 10 | 示例 2: 11 | 输入: [-2,0,-1] 12 | 输出: 0 13 | 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 14 | */ 15 | 16 | class Solution 17 | { 18 | public: 19 | int maxProduct(vector &nums) 20 | { 21 | /** 22 | 对于乘法,需要注意,负数乘以负数,会变成正数,所以处理起来,跟连续子数组的最大和不太一样。 23 | dp_max[i]:以索引为 i 的数结尾的连续子数组的最大积; 24 | dp_min[i]:以索引为 i 的数结尾的连续子数组的最小积; 25 | 26 | 状态转移方程为: 27 | dp_min[i] = min(nums[i], min(dp_min[i - 1] * nums[i], dp_max[i - 1] * nums[i])); 28 | dp_max[i] = max(nums[i], max(dp_min[i - 1] * nums[i], dp_max[i - 1] * nums[i])); 29 | */ 30 | if (nums.empty()) 31 | return 0; 32 | if (nums.size() == 1) 33 | return nums[0]; 34 | int m = nums[0]; 35 | vector dp_min(nums.size(), 1); 36 | vector dp_max(nums.size(), 1); 37 | dp_min[0] = dp_max[0] = nums[0]; 38 | for (int i = 1; i < nums.size(); ++i) 39 | { 40 | dp_min[i] = min(nums[i], min(dp_min[i - 1] * nums[i], dp_max[i - 1] * nums[i])); 41 | dp_max[i] = max(nums[i], max(dp_min[i - 1] * nums[i], dp_max[i - 1] * nums[i])); 42 | m = max(m, dp_max[i]); 43 | } 44 | return m; 45 | } 46 | }; -------------------------------------------------------------------------------- /LeetCode/167-两数之和2-输入有序数组/twoSum.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/two-_sum-ii-input-array-is-sorted/submissions/ 4 | 5 | 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 6 | 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。 7 | 说明: 8 | 返回的下标值(index1 和 index2)不是从零开始的。 9 | 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 10 | 11 | 示例: 12 | 输入: numbers = [2, 7, 11, 15], target = 9 13 | 输出: [1, 2] 14 | 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。 15 | 16 | """ 17 | 18 | 19 | class Solution(object): 20 | def two_sum(self, numbers, target): 21 | """ 22 | 提示: 23 | 左右两个指针 left, right 分别指向首尾元素,_sum 等于 left, right 指向的元素之和。 24 | _sum 和 target比较,当 _sum 小于 target 时,left 往右走,当 _sum 大于 target 的时候,right 往左走。 25 | 26 | :type numbers: List[int] 27 | :type target: int 28 | :rtype: List[int] 29 | """ 30 | left = 0 31 | right = len(numbers) - 1 32 | _sum = 0 33 | while left < right: 34 | _sum = numbers[left] + numbers[right] 35 | if _sum < target: 36 | left += 1 37 | elif _sum > target: 38 | right -= 1 39 | else: 40 | return [left + 1, right + 1] # 因为题目中的下标值,指的是第几个数而不是索引 41 | 42 | -------------------------------------------------------------------------------- /LeetCode/189-旋转数组/main189.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void rotate(vector& nums, int k) { 4 | int size = nums.size(); 5 | if (size < 1) 6 | return; 7 | k %= size; 8 | int left = 0, right = size - 1; 9 | reserve(nums, left, right); 10 | reserve(nums, left, k - 1); 11 | reserve(nums, k, right); 12 | } 13 | 14 | void swap(int& a, int& b) { 15 | //不用其他变量实现两个数的交换: 16 | //https://blog.csdn.net/M771310443/article/details/21245675 17 | // 两个相同的数与一个不同的数异或,就等于这个不同的数 18 | a = a ^ b; 19 | b = a ^ b; 20 | a = a ^ b; 21 | } 22 | 23 | void reserve(vector& nums, int left, int right) { 24 | while (right > left) { 25 | swap(nums[right], nums[left]); 26 | left++, right--; 27 | } 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /LeetCode/198-打家劫舍/leetcode198.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int rob(vector& nums) { 4 | int size = nums.size(); 5 | if (size == 0) 6 | return 0; 7 | else if (size == 1) 8 | return nums[0]; 9 | else if (size == 2) 10 | return max(nums[0], nums[1]); 11 | 12 | int dp[size] = {0}; 13 | dp[0] = nums[0], dp[1] = max(nums[0], nums[1]); 14 | for (int i = 2; i < size; ++i) 15 | dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]); 16 | return dp[size - 1]; 17 | } 18 | }; -------------------------------------------------------------------------------- /LeetCode/198-打家劫舍/rob.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf:8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/house-robber 4 | 5 | 你是一个专业的小偷,计划偷窃沿街的房屋。 6 | 每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统, 7 | 如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 8 | 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 9 | 10 | 示例 1: 11 | 输入: [1,2,3,1] 12 | 输出: 4 13 | 解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 14 | 偷窃到的最高金额 = 1 + 3 = 4 。 15 | 16 | 示例 2: 17 | 输入: [2,7,9,3,1] 18 | 输出: 12 19 | 解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 20 | 偷窃到的最高金额 = 2 + 9 + 1 = 12 。 21 | 22 | """ 23 | 24 | 25 | class Solution: 26 | def rob(self, nums: list) -> int: 27 | """ 28 | 提示:动态规划 29 | 令 dp[i] 为偷了在闭区间 [0, i] 的房子,得到的最高金额。 30 | 则遇到索引为 i 的房子,有两种情况: 31 | 若偷:dp[i] = dp[i-2] + nums[i]; 32 | 若不偷:dp[i] = dp[1-1]。 33 | 34 | 状态转移方程为: 35 | dp[i] = max(dp[i-1], dp[i-2] + nums[i]) if i >= 2 36 | 37 | """ 38 | size = len(nums) 39 | if size == 0: 40 | return 0 41 | elif size == 1: 42 | return nums[0] 43 | elif size == 2: 44 | return max(nums) 45 | 46 | dp = [0] * size 47 | dp[0], dp[1] = nums[0], max(nums[:2]) 48 | for i in range(2, size): 49 | dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) 50 | return dp[-1] 51 | 52 | -------------------------------------------------------------------------------- /LeetCode/2-两数相加/addTwoNumbers.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/add-two-numbers/ 3 | 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 4 | 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 5 | 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 6 | 7 | 示例: 8 | 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 9 | 输出:7 -> 0 -> 8 10 | 原因:342 + 465 = 807 11 | 12 | """ 13 | 14 | # Definition for singly-linked list. 15 | # class ListNode: 16 | # def __init__(self, x): 17 | # self.val = x 18 | # self.next = None 19 | 20 | class Solution(object): 21 | def addTwoNumbers(self, l1, l2): 22 | head = ListNode(0) # 头节点的指针 23 | p = head 24 | p1 = l1 25 | p2 = l2 26 | carry = 0 # 是否进位 27 | while p1 and p2: 28 | s, carry = self.ifcarry(p1.val, p2.val, carry) 29 | p.next = ListNode(s) 30 | p, p1, p2 = p.next, p1.next, p2.next 31 | p1 = p1 if p1 else p2 32 | while carry: 33 | if p1: 34 | s, carry = self.ifcarry(p1.val, carry) 35 | p.next = ListNode(s) 36 | p, p1 = p.next, p1.next 37 | else: 38 | p.next = ListNode(carry) 39 | p = p.next 40 | break 41 | p.next = p1 42 | return head.next 43 | 44 | def ifcarry(self, x, y, c=0): 45 | """ 46 | 是否进位 47 | """ 48 | carry = 0 49 | s = x + y + c 50 | if s >= 10: 51 | s = s - 10 52 | carry = 1 53 | return s, carry 54 | 55 | -------------------------------------------------------------------------------- /LeetCode/2-两数相加/main2.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | https://leetcode-cn.com/problems/add-two-numbers/ 3 | 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 4 | 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 5 | 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 6 | 7 | 示例: 8 | 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 9 | 输出:7 -> 0 -> 8 10 | 原因:342 + 465 = 807 11 | */ 12 | 13 | /** 14 | * Definition for singly-linked list. 15 | * struct ListNode { 16 | * int val; 17 | * ListNode *next; 18 | * ListNode(int x) : val(x), next(NULL) {} 19 | * }; 20 | */ 21 | class Solution 22 | { 23 | public: 24 | ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) 25 | { 26 | int carry = 0; 27 | ListNode *p1 = l1; 28 | ListNode *p2 = l2; 29 | ListNode *head = new ListNode(0); 30 | ListNode *p = head; 31 | int s, x, y = 0; 32 | while (p1 || p2) 33 | { 34 | if (p1 && p2) 35 | s = p1->val + p2->val + carry; 36 | else if (p1 && !p2) 37 | s = p1->val + carry; 38 | else if (!p1 && p2) 39 | s = p2->val + carry; 40 | x = s % 10; 41 | carry = s / 10; 42 | p->next = new ListNode(x); 43 | p = p->next; 44 | if (p1) 45 | p1 = p1->next; 46 | if (p2) 47 | p2 = p2->next; 48 | } 49 | if (carry) 50 | p->next = new ListNode(carry); 51 | return head->next; 52 | } 53 | }; -------------------------------------------------------------------------------- /LeetCode/200-岛屿数量/leetcode200.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | https://leetcode-cn.com/problems/number-of-islands/solution/number-of-islands-shen-du-you-xian-bian-li-dfs-or-/ 3 | */ 4 | 5 | class Solution { 6 | private: 7 | vector > directions {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; 8 | 9 | public: 10 | int numIslands(vector>& grid) { 11 | // 深度优先搜索 dfs 12 | if (grid.empty()) 13 | return 0; 14 | int m = grid.size(); 15 | int n = grid[0].size(); 16 | int count = 0; 17 | vector > marked(m, vector(n, false)); 18 | for (int i = 0; i < m; ++i) 19 | for (int j = 0; j < n; ++j) 20 | if (!marked[i][j] && grid[i][j] == '1') 21 | { 22 | count++; 23 | dfs(grid, i, j, m, n, marked); 24 | } 25 | return count; 26 | } 27 | 28 | void dfs(vector >& grid, int i, int j, int m, int n, vector >& marked) 29 | { 30 | marked[i][j] = true; 31 | for (int direct = 0; direct < directions.size(); ++direct) 32 | { 33 | int new_i = i + directions[direct][0]; 34 | int new_j = j + directions[direct][1]; 35 | if (new_i >= 0 && new_i < m && new_j >= 0 && new_j < n && !marked[new_i][new_j] && grid[new_i][new_j] == '1') 36 | dfs(grid, new_i, new_j, m, n, marked); 37 | } 38 | } 39 | }; 40 | 41 | -------------------------------------------------------------------------------- /LeetCode/217-存在重复元素/duplicate.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/contains-duplicate 3 | https://leetcode-cn.com/problems/contains-duplicate/solution/cun-zai-zhong-fu-de-yuan-su-python3ji-he-fa-by-pan/ 4 | 5 | 给定一个整数数组,判断是否存在重复元素。 6 | 如果任何值在数组中出现至少两次,函数返回 true。 7 | 如果数组中每个元素都不相同,则返回 false。 8 | 9 | 示例 1: 10 | 输入: [1,2,3,1] 11 | 输出: true 12 | 13 | 示例 2: 14 | 输入: [1,2,3,4] 15 | 输出: false 16 | 17 | 示例 3: 18 | 输入: [1,1,1,3,3,4,3,2,4,2] 19 | 输出: true 20 | 21 | """ 22 | from typing import List 23 | 24 | 25 | class Solution: 26 | def containsDuplicate(self, nums: List[int]) -> bool: 27 | """ 28 | 提示:集合 set() 29 | """ 30 | return len((set(nums))) != len(nums) 31 | 32 | def containsDuplicate2(self, nums: List[int]) -> bool: 33 | """ 34 | 提示:哈希表 35 | 如果后面的数在哈希表里出现过,那必有重合 36 | """ 37 | dic = {} 38 | for i in nums: 39 | if dic.get(i): 40 | return True 41 | dic[i] = 1 42 | return False 43 | 44 | def containsDuplicate2(self, nums: List[int]) -> bool: 45 | """ 46 | 提示:排序 47 | 排序的列表,重合的元素必相邻 48 | """ 49 | nums.sort() 50 | for i in range(len(nums) - 1): 51 | if nums[i + 1] == nums[i]: 52 | return True 53 | return False 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /LeetCode/217-存在重复元素/main217.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool containsDuplicate(vector& nums) { 4 | // 使用集合,vector 的长度与 set 不相等,说明有重复 5 | set sn(nums.begin(), nums.end()); 6 | return !(sn.size() == nums.size()); 7 | } 8 | 9 | bool containsDuplicate2(vector& nums) { 10 | // 使用 hash map 11 | map hash_nums; 12 | for (int i = 0; i < nums.size(); ++i) { 13 | if (hash_nums.count(nums[i])) 14 | return true; 15 | hash_nums[nums[i]]++; 16 | } 17 | return false; 18 | } 19 | 20 | bool containsDuplicate3(vector& nums) { 21 | //使用排序,之后判断相邻的元素是否相等 22 | if (nums.size() <= 1) 23 | return false; 24 | sort(nums.begin(), nums.end()); 25 | vector::iterator start = nums.begin(); 26 | vector::iterator finish = nums.end(); 27 | for (; start != finish - 1; ++start) { 28 | if ((*start) == *(start + 1)) 29 | return true; 30 | } 31 | return false; 32 | } 33 | }; -------------------------------------------------------------------------------- /LeetCode/26-删除排序数组中的重复项/main26.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeDuplicates(vector& nums) { 4 | int size = nums.size(); 5 | if (size < 2) { 6 | return size; 7 | } 8 | int p_this = 0; 9 | int p_next = 1; 10 | while (p_next < size) { 11 | if (nums[p_next] == nums[p_this]) 12 | p_next++; 13 | else 14 | nums[++p_this] = nums[p_next++]; 15 | } 16 | return p_this + 1; 17 | } 18 | }; -------------------------------------------------------------------------------- /LeetCode/26-删除排序数组中的重复项/remove.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array 3 | 4 | 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 5 | 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 6 | 7 | 示例 1: 8 | 给定数组 nums = [1,1,2], 9 | 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 10 | 你不需要考虑数组中超出新长度后面的元素。 11 | 12 | 示例 2: 13 | 给定 nums = [0,0,1,1,1,2,2,3,3,4], 14 | 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 15 | 你不需要考虑数组中超出新长度后面的元素。 16 | """ 17 | from typing import List 18 | 19 | 20 | class Solution: 21 | def removeDuplicates(self, nums: List[int]) -> int: 22 | """ 23 | 提示: 24 | 让 this 指向数字第一次出现的位置,next 一直往后加,直到到达最后一个元素。 25 | 如果 next 处的元素与 this 处的元素相同,则 next 自增,this 不动 26 | 如果 next 处的元素与 this 处的元素不同,则让 this+1,并把 next 处的元素放到新的 this 位置处,next 再自增。 27 | 28 | """ 29 | size = len(nums) 30 | if size < 2: 31 | return size 32 | this = 0 33 | next = 1 34 | while next < size: 35 | if nums[this] == nums[next]: 36 | next += 1 37 | else: 38 | this += 1 39 | nums[this] = nums[next] 40 | next += 1 41 | return this + 1 42 | -------------------------------------------------------------------------------- /LeetCode/268-缺失数字/leetcode268.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | https://leetcode-cn.com/problems/missing-number 3 | 给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。 4 | 5 | 示例 1: 6 | 输入: [3,0,1] 7 | 输出: 2 8 | 9 | 示例 2: 10 | 输入: [9,6,4,2,3,5,7,0,1] 11 | 输出: 8 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | 22 | class Solution { 23 | public: 24 | int missingNumber(vector& nums) { 25 | /* 26 | 基本方法如:排序,建立哈希表,略去 27 | 28 | 方法一:使用异或运算,使时间复杂度为 O(n),空间复杂度 O(1) 29 | 30 | 包含数字 0~n 的序列按理是要用 n+1 长度的数组存储,但该序列缺少了一个数字 x,x 属于区间 [0, n], 31 | 由于相同的数字异或为 0,则将索引 0~n 与序列依次异或,得到的最终结果就是缺失的数字。 32 | 33 | 例如 nums = [3, 0, 1],若不缺少 2,则用长度为 4 的数组来存储,该数组索引为 0~3, 34 | x = 3 ^ 0 ^ 1 ^ 0 ^ 1 ^ 2 ^ 3 35 | = (0 ^ 0) ^ (1 ^ 1) ^ 2 ^ (3 ^ 3) 36 | = 2 37 | 38 | 方法二:数学 39 | 区间 [0, n] 上的数字之和为 s1, nums 是区间 [0, n] 中缺少一个数字 x 组成的数组,设对 nums 求和为 s2, 40 | 则 x = s1 - s2 41 | */ 42 | 43 | 44 | } 45 | }; 46 | 47 | -------------------------------------------------------------------------------- /LeetCode/28-实现strStr()/main28.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int strStr(string haystack, string needle) { 4 | if (!needle.size()) 5 | return 0; 6 | if (!haystack.size())// || needle.size() > haystack.size()) 7 | return -1; 8 | 9 | int i = 0, j = 0; 10 | 11 | while (i < int(haystack.size() - needle.size() + 1)) 12 | //haystack.size() - needle.size() + 1是无符号整型, 13 | //有符号与无符号比较,自动把有符号转换成无符号 14 | { 15 | //cout << i << ' ' << haystack.size() << ' ' << needle.size() << ' ' << haystack.size() - needle.size() + 1 << endl; 16 | while (j < needle.size()) 17 | { 18 | if (haystack[i] != needle[j]) 19 | { 20 | i = i - j + 1; 21 | j = 0; 22 | break; 23 | } 24 | else 25 | { 26 | ++i; 27 | ++j; 28 | } 29 | } 30 | if (j == needle.size()) 31 | return i - j; 32 | } 33 | return -1; 34 | } 35 | }; -------------------------------------------------------------------------------- /LeetCode/283-移动零/moveZeros.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/move-zeroes 3 | 4 | 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 5 | 6 | 示例: 7 | 输入: [0,1,0,3,12] 8 | 输出: [1,3,12,0,0] 9 | 10 | 说明: 11 | 必须在原数组上操作,不能拷贝额外的数组。 12 | 尽量减少操作次数。 13 | """ 14 | from typing import List 15 | 16 | 17 | class Solution: 18 | def moveZeroes(self, nums: List[int]) -> None: 19 | """ 20 | 提示:双指针 21 | 指针 p1 指向可以被覆盖的位置,指针 p2 指向当前遍历到的位置 22 | p2 每次遇到零就自增,p1 不变; 23 | 遇到非零,就将当前值覆盖掉 p1 位置的元素,然后 p1, p2 同时自增。 24 | 当 p2 到达数组尾部的时候,p1 到数组尾部的元素再全部填充零 25 | 26 | Do not return anything, modify nums in-place instead. 27 | """ 28 | size = len(nums) 29 | p1 = p2 = 0 30 | while p2 < size: 31 | if nums[p2] != 0: 32 | nums[p1] = nums[p2] 33 | p1 += 1 34 | p2 += 1 35 | else: 36 | p2 += 1 37 | while p1 < size: 38 | nums[p1] = 0 39 | p1 += 1 40 | 41 | def moveZeroes2(self, nums: List[int]) -> None: 42 | """ 43 | 提示:冒泡排序 44 | 相邻元素比较,使零沉底,几轮交换下来,零就在数组尾部。 45 | """ 46 | pass -------------------------------------------------------------------------------- /LeetCode/300-最长上升子序列/leetcode300.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | /* 10 | https://leetcode-cn.com/problems/longest-increasing-subsequence 11 | 12 | 给定一个无序的整数数组,找到其中最长上升子序列的长度。 13 | 14 | 示例: 15 | 输入: [10,9,2,5,3,7,101,18] 16 | 输出: 4 17 | 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 18 | 19 | 说明: 20 | 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。 21 | 你算法的时间复杂度应该为 O(n2) 。 22 | 23 | */ 24 | 25 | class Solution { 26 | public: 27 | int lengthOfLIS(vector& nums) { 28 | /* 29 | 提示:动态规划 30 | 令 dp[i] 表示含 nums[i] 的最长上升子序列的长度,不是闭区间 [0, i]。 31 | dp[i] = max(dp[i], dp[j] + 1) 其中,j 属于 [0, i) 且 num[j] < num[i] 32 | */ 33 | if (nums.empty()) 34 | return 0; 35 | vector dp(nums.size(), 1); 36 | int max_length = 1; 37 | for (int i = 1; i < nums.size(); ++i) 38 | for (int j = i - 1; j >= 0; --j) 39 | { 40 | if (nums[j] < nums[i]) 41 | { 42 | dp[i] = max(dp[j] + 1, dp[i]); 43 | max_length = max(dp[i], max_length); 44 | } 45 | } 46 | return max_length; 47 | } 48 | }; 49 | 50 | int main(int argc, char** argv) 51 | { 52 | ; 53 | } -------------------------------------------------------------------------------- /LeetCode/322-零钱兑换/coinChange.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -* 2 | """ 3 | https://leetcode-cn.com/problems/coin-change 4 | 5 | 给定不同面额的硬币 coins 和一个总金额 amount。 6 | 编写一个函数来计算可以凑成总金额所需的最少的硬币个数。 7 | 如果没有任何一种硬币组合能组成总金额,返回 -1。 8 | 9 | 示例 1: 10 | 输入: coins = [1, 2, 5], amount = 11 11 | 输出: 3 12 | 解释: 11 = 5 + 5 + 1 13 | 14 | 示例 2: 15 | 输入: coins = [2], amount = 3 16 | 输出: -1 17 | 18 | 说明: 19 | 你可以认为每种硬币的数量是无限的。 20 | 21 | """ 22 | from typing import List 23 | 24 | 25 | class Solution: 26 | def coinChange(self, coins: List[int], amount: int) -> int: 27 | """ 28 | 提示: 29 | 完全背包问题,用动态规划求解 30 | 令 dp[i] 为凑足总金额为 i 的钱需要的最少硬币数,则状态转换方程为: 31 | 32 | 0 if i == 0 33 | dp(i) = / 34 | \ 35 | min(dp[i], dp[i - coin] + 1) if i >= coin,其中 coin 是 coins 中的某一枚硬币面额。 36 | 37 | """ 38 | # 使 amount+1 填充备忘录 dp,如果 dp 里的数据没有修改,那么一定大于 amount。 39 | # 所以在 return 的时候可以作判断, 40 | # 如果 dp[i] 未被修改,说明找不到合适的硬币凑成该金额,返回 -1 就行。 41 | 42 | dp = [amount + 1 for x in range(amount + 1)] 43 | dp[0] = 0 44 | for coin in coins: 45 | for i in range(coin, amount + 1): 46 | dp[i] = min(dp[i], dp[i - coin] + 1) 47 | return -1 if dp[amount] > amount else dp[amount] 48 | 49 | 50 | if __name__ == "__main__": 51 | f = Solution() 52 | coins = [1, 2, 5] 53 | amount = 11 54 | print(f.coinChange(coins, amount)) 55 | -------------------------------------------------------------------------------- /LeetCode/322-零钱兑换/leetcode322.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int coinChange(vector& coins, int amount) { 4 | if (amount < 0 || coins.empty()) 5 | return -1; 6 | vector dp(amount + 1, amount + 1); 7 | dp[0] = 0; 8 | for (int i = 0; i < coins.size(); ++i) 9 | for (int j = coins[i]; j <= amount; ++j) 10 | dp[j] = min(dp[j], dp[j - coins[i]] + 1); 11 | return dp[amount] > amount ? -1 : dp[amount]; 12 | } 13 | }; -------------------------------------------------------------------------------- /LeetCode/324-摆动排序2/main324.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void wiggleSort(vector& nums) { 4 | sort(nums.begin(), nums.end(), comp); 5 | int mid = nums.size() / 2; 6 | // 将 nums 分成小的第一部分 nums[mid:] 和较大的第二部分 nums[:mid] 7 | vector part1(nums.begin() + mid, nums.end()); 8 | vector part2(nums.begin(), nums.begin() + mid); 9 | int p1 = 0, p2 = 0; 10 | int i = 0; 11 | while (i < nums.size()) 12 | { 13 | // 如果 nums 的长度为奇数,第一部分必定多于第二部分, 14 | // 如 [3, 2, 1],part1: [2, 1],part2: [3] 15 | if (p1 < part1.size()) 16 | nums[i++] = part1[p1++]; 17 | if (p2 < part2.size()) 18 | nums[i++] = part2[p2++]; 19 | } 20 | } 21 | 22 | // sort 里的 comp 不能是类的成员函数,故加 static 23 | static bool comp(int x, int y) // 按降序排序,大的在前面。 24 | { 25 | return x > y; 26 | } 27 | }; -------------------------------------------------------------------------------- /LeetCode/324-摆动排序2/wiggle-sort-ii.py: -------------------------------------------------------------------------------- 1 | # -*- coding:itf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/wiggle-sort-ii/ 4 | 给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]... 的顺序。 5 | 6 | 示例 : 7 | 输入: nums = [1, 5, 1, 1, 6, 4] 8 | 输出: 一个可能的答案是 [1, 4, 1, 5, 1, 6] 9 | 10 | """ 11 | 12 | class Solution: 13 | def wiggleSort(self, nums) -> None: 14 | """ 15 | 提示: 16 | 对数组排排序,如 [1, 2, 3, 4],将其分成 [1, 2] 和 [3, 4] 两部分, 17 | 每次从这两个子数组中拿出一个数,组成新的数组 [1, 3, 2, 4]。 18 | 19 | 但对于实例 [4, 5, 5, 6], 将其分成 [4, 5], [5, 6] 两部分, 20 | 每次从这两个子数组中拿出一个数组成新的数组 [4, 5, 5, 6]。不满足摆动排序。 21 | 我们可以对该实例逆序,得到 [6, 5, 5, 4],将其分成 [5, 4], [6, 5] 两部分, 22 | 这样中间一段重复的数字 5 在左边数组中是第一个用到,在右边数组是最后一个用到,因此在新的数组中它们被分开了。 23 | 每次从这两个子数组中拿出一个数组成新的数组 [5, 6, 4, 5]。满足摆动排序。 24 | 25 | Do not return anything, modify nums in-place instead. 26 | """ 27 | nums.sort(reverse=True) 28 | mid = len(nums) // 2 29 | nums[1::2], nums[0::2] = nums[:mid], nums[mid:] -------------------------------------------------------------------------------- /LeetCode/349-两个数组的交集/349-interSection.py: -------------------------------------------------------------------------------- 1 | # -*- coding:itf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/intersection-of-two-arrays 4 | 5 | 给定两个数组,编写一个函数来计算它们的交集。 6 | 7 | 示例 1: 8 | 输入: nums1 = [1,2,2,1], nums2 = [2,2] 9 | 输出: [2] 10 | 11 | 示例 2: 12 | 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] 13 | 输出: [9,4] 14 | 15 | 说明: 16 | 17 | 输出结果中的每个元素一定是唯一的。 18 | 我们可以不考虑输出结果的顺序。 19 | 20 | """ 21 | from typing import List 22 | 23 | 24 | 25 | class Solution: 26 | def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: 27 | return list(set(nums1) & set(nums2)) -------------------------------------------------------------------------------- /LeetCode/349-两个数组的交集/350-interSection2.py: -------------------------------------------------------------------------------- 1 | # -*- coding:itf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/intersection-of-two-arrays-ii 4 | 5 | 给定两个数组,编写一个函数来计算它们的交集。 6 | 7 | 示例 1: 8 | 输入: nums1 = [1,2,2,1], nums2 = [2,2] 9 | 输出: [2,2] 10 | 11 | 示例 2: 12 | 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] 13 | 输出: [4,9] 14 | 15 | 说明: 16 | 17 | 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。 18 | 我们可以不考虑输出结果的顺序。 19 | 20 | """ 21 | from typing import List 22 | 23 | 24 | class Solution: 25 | def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]: 26 | """ 27 | 提示: 28 | 若 nums1 与 nums2 都有序,使用双指针一个一个比较,遍历一次。 29 | """ 30 | nums1.sort() 31 | nums2.sort() 32 | res = [] 33 | i = j = 0 34 | while i < len(nums1) and j < len(nums2): 35 | if nums1[i] == nums2[j]: 36 | res.append(nums1[i]) 37 | i += 1 38 | j += 1 39 | elif nums1[i] < nums2[j]: 40 | i += 1 41 | else: 42 | j += 1 43 | return res 44 | -------------------------------------------------------------------------------- /LeetCode/35-搜索插入位置/main35.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int searchInsert(vector& nums, int target) { 4 | if (nums.empty()) 5 | return 0; 6 | if (target < nums[0]) 7 | return 0; 8 | if (target > nums[nums.size() - 1]) 9 | return nums.size(); 10 | int left = 0, right = nums.size() - 1; 11 | int mid = 0; 12 | while (left <= right) // 不可缺少等于号 13 | { 14 | mid = (left + right) / 2; 15 | if (target < nums[mid]) 16 | right = mid - 1; 17 | else if (target > nums[mid]) 18 | left = mid + 1; 19 | else 20 | return mid; 21 | } 22 | if (target <= nums[mid]) 23 | return mid; 24 | else 25 | return mid + 1; 26 | } 27 | }; -------------------------------------------------------------------------------- /LeetCode/35-搜索插入位置/searchInsert.py: -------------------------------------------------------------------------------- 1 | # -*- coding:itf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/search-insert-position/ 4 | 5 | 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。 6 | 如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 7 | 你可以假设数组中无重复元素。 8 | 9 | 示例 1: 10 | 输入: [1,3,5,6], 5 11 | 输出: 2 12 | 13 | 示例 2: 14 | 输入: [1,3,5,7,9], 4 15 | 输出: 2 16 | 17 | 示例 3: 18 | 输入: [1,3,5,7,9], 6 19 | 输出: 3 20 | 21 | """ 22 | 23 | 24 | class Solution(object): 25 | def searchInsert(self, nums, target): 26 | """ 27 | 提示: 28 | 二分查找,时间复杂度是 O(logn),注意临界值。 29 | """ 30 | if target <= nums[0]: 31 | return 0 32 | if target > nums[-1]: 33 | return len(nums) 34 | 35 | left, right = 0, len(nums)-1 36 | while left <= right: 37 | mid = (left + right) // 2 38 | if target < nums[mid]: 39 | right = mid - 1 40 | elif target > nums[mid]: 41 | left = mid + 1 42 | else: 43 | return mid 44 | if target < nums[mid]: 45 | return mid 46 | if target > nums[mid]: 47 | return mid + 1 48 | -------------------------------------------------------------------------------- /LeetCode/367-有效的完全平方数/isPerfectSquare.py: -------------------------------------------------------------------------------- 1 | # -*- coding:itf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/valid-perfect-square 4 | 5 | 给定一个正整数 num,编写一个函数,如果 num 是一个完全平方数,则返回 True,否则返回 False。 6 | 说明:完全平方数即该数字能够分解为两个正整数的平方。不要使用任何内置的库函数,如 sqrt。 7 | 8 | 示例 1: 9 | 输入:16 10 | 输出:True 11 | 12 | 示例 2: 13 | 输入:14 14 | 输出:False 15 | 16 | """ 17 | 18 | 19 | class Solution: 20 | def isPerfectSquare(self, num: int) -> bool: 21 | left = 1 22 | right = num 23 | while left <= right: 24 | mid = (left + right)//2 25 | t = mid ** 2 26 | if t > num: 27 | right = mid - 1 28 | elif t < num: 29 | left = mid + 1 30 | else: 31 | return True 32 | return False -------------------------------------------------------------------------------- /LeetCode/374-猜数字大小/guessNumber.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/guess-number-higher-or-lower 4 | 5 | 我们正在玩一个猜数字游戏。 游戏规则如下: 6 | 我从 1 到 n 选择一个数字。 你需要猜我选择了哪个数字。 7 | 每次你猜错了,我会告诉你这个数字是大了还是小了。 8 | 你调用一个预先定义好的接口 guess(int num),它会返回 3 个可能的结果(-1,1 或 0): 9 | 10 | -1 : 我的数字比较小 11 | 1 : 我的数字比较大 12 | 0 : 恭喜!你猜对了! 13 | 14 | 示例 : 15 | 输入: n = 10, pick = 6 16 | 输出: 6 17 | 18 | """ 19 | 20 | # The guess API is already defined for you. 21 | # @param num, your guess 22 | # @return -1 if my number is lower, 1 if my number is higher, otherwise return 0 23 | # def guess(num): 24 | 25 | 26 | class Solution(object): 27 | def guessNumber(self, n): 28 | if n <= 1: 29 | return n 30 | left = 0 31 | right = n 32 | while left <= right: 33 | mid = (left + right)//2 34 | if guess(mid) == 1: 35 | left = mid + 1 36 | elif guess(mid) == -1: 37 | right = mid-1 38 | else: 39 | return mid 40 | -------------------------------------------------------------------------------- /LeetCode/387-字符串中的第一个唯一字符/leetcode387.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int firstUniqChar(string s) { 4 | int count[26] = {0}; 5 | for (int i = 0; s[i] != '\0'; ++i) 6 | { 7 | count[s[i] - 'a']++; 8 | } 9 | 10 | for (int i = 0; s[i] != '\0'; ++i) 11 | { 12 | if (count[s[i] - 'a'] == 1) 13 | return i; 14 | } 15 | return -1; 16 | } 17 | }; -------------------------------------------------------------------------------- /LeetCode/387-字符串中的第一个唯一字符/leetcode387.py: -------------------------------------------------------------------------------- 1 | """ 2 | 链接:https://leetcode-cn.com/problems/first-unique-character-in-a-string 3 | 4 | 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 5 | 6 | 案例: 7 | s = "leetcode" 8 | 返回 0. 9 | 10 | s = "loveleetcode", 11 | 返回 2. 12 | 13 | """ 14 | 15 | class Solution: 16 | def firstUniqChar(self, s: str) -> int: 17 | """ 18 | 提示: 19 | 哈希表 20 | """ -------------------------------------------------------------------------------- /LeetCode/392-判断子序列/leetcode392.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isSubsequence(string s, string t) { 4 | int i = 0; 5 | for (int j = 0; j < t.size(); ++j) 6 | if (i < s.size()) 7 | { 8 | if (s[i] == t[j]) 9 | i++; 10 | } // 花括号别省,不然以为下面的 else 是第二个 if 的。 11 | else 12 | break; 13 | return i == s.size(); 14 | } 15 | }; -------------------------------------------------------------------------------- /LeetCode/392-判断子序列/leetcode392.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/is-subsequence 3 | 4 | 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 5 | 你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。 6 | 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。 7 | 8 | 示例 1: 9 | s = "abc", t = "ahbgdc" 10 | 11 | 返回 true. 12 | 13 | 示例 2: 14 | s = "axc", t = "ahbgdc" 15 | 16 | 返回 false. 17 | 18 | """ 19 | 20 | 21 | class Solution: 22 | def isSubsequence(self, s: str, t: str) -> bool: 23 | """ 24 | 提示: 25 | 顺序比较就好,不需要动态规划搞的那么复杂,复杂度最多为 O(t的长度) 26 | """ 27 | i = 0 28 | for ch in t: 29 | if i < len(s): 30 | if s[i] == ch: 31 | i += 1 32 | else: 33 | break 34 | return i == len(s) -------------------------------------------------------------------------------- /LeetCode/406-根据身高重建队列/leetcode406.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | https://leetcode-cn.com/problems/queue-reconstruction-by-height 3 | 4 | 假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示, 5 | 其中 h 是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 6 | 编写一个算法来重建这个队列。 7 | 8 | 注意: 9 | 总人数少于1100人。 10 | 11 | 示例: 12 | 输入: 13 | [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] 14 | 15 | 输出: 16 | [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] 17 | */ 18 | 19 | class Solution 20 | { 21 | public: 22 | vector> reconstructQueue(vector> &people) 23 | { 24 | /* 25 | 思路: 26 | 按第一个元素(身高)降序排序,第二个元素(人数)升序排序。 27 | 再将第二个元素的位置将元素插入到数组中,画个图就全部明白了。 28 | */ 29 | // 身高降序排列,人数升序排列 30 | sort(people.begin(), people.end(), cmp); 31 | vector> res; 32 | for (int i = 0; i < people.size(); i++) 33 | res.insert(res.begin() + people[i][1], people[i]); 34 | return res; 35 | } 36 | 37 | static bool cmp(const vector &a, const vector &b) // 自定义的比较规则 cmp 得是静态成员函数 38 | // a, b 均是一个数对,按第一个元素(身高)降序排序,第二个元素(人数)升序排序 39 | { 40 | if (a[0] > b[0]) 41 | return true; 42 | if (a[0] == b[0] && a[1] < b[1]) 43 | return true; 44 | return false; 45 | } 46 | }; -------------------------------------------------------------------------------- /LeetCode/416-分割等和子集/leetcode416.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | 8 | class Solution { 9 | public: 10 | bool canPartition(vector& nums) { 11 | int s = sum(nums); 12 | if (s & 1) 13 | return false; 14 | s = s / 2; // 背包容量 15 | 16 | vector dp(s + 1, 0); 17 | dp[0] = 1; 18 | 19 | for (int i = 0; i < nums.size(); ++i) 20 | for (int j = s; j >= nums[i]; --j) // 01背包 21 | { 22 | dp[j] = dp[j - nums[i]] + dp[j]; 23 | // leetcode 测试不通过,因为有大数相加 int 溢出,使用 canPartition2 稍微改一下就好了 24 | } 25 | return bool(dp[s]); 26 | } 27 | 28 | bool canPartition2(vector& nums) { 29 | int s = sum(nums); 30 | if (s & 1) 31 | return false; 32 | s = s / 2; // 背包容量 33 | vector dp(s + 1, false); 34 | dp[0] = true; 35 | 36 | for (int i = 0; i < nums.size(); ++i) 37 | for (int j = s; j >= nums[i]; --j) // 01背包 38 | { 39 | dp[j] = dp[j - nums[i]] || dp[j]; 40 | } 41 | return dp[s]; 42 | } 43 | 44 | int sum(vector nums) 45 | { 46 | int s = 0; 47 | for (int i = 0; i < nums.size(); ++i) 48 | s += nums[i]; 49 | return s; 50 | } 51 | }; 52 | 53 | int main() 54 | { 55 | vector nums{1, 5, 11, 5}; 56 | Solution f; 57 | cout << f.canPartition(nums) << endl; 58 | cout << f.canPartition2(nums) << endl; 59 | 60 | getchar(); 61 | } -------------------------------------------------------------------------------- /LeetCode/461-汉明距离/leetcode461.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | /* 10 | 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。 11 | 给出两个整数 x 和 y,计算它们之间的汉明距离。 12 | 13 | 注意: 14 | 0 ≤ x, y < 231. 15 | 16 | 示例: 17 | 输入: x = 1, y = 4 18 | 输出: 2 19 | 20 | 解释: 21 | 1 (0 0 0 1) 22 | 4 (0 1 0 0) 23 | ↑ ↑ 24 | 25 | 上面的箭头指出了对应二进制位不同的位置 26 | 27 | 来源:力扣(LeetCode) 28 | 链接:https://leetcode-cn.com/problems/hamming-distance 29 | 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 30 | */ 31 | 32 | class Solution { 33 | public: 34 | int hammingDistance(int x, int y) { 35 | /* 36 | 提示: 37 | 异或运算,再求二进制中 1 的个数 38 | */ 39 | } 40 | }; 41 | 42 | int main(int argc, char** argv) 43 | { 44 | 45 | } -------------------------------------------------------------------------------- /LeetCode/474-一和零/leetcode474.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | 8 | class Solution { 9 | public: 10 | int findMaxForm(vector& strs, int m, int n) { 11 | vector > dp(m + 1, vector(n + 1, 0)); 12 | for (int i = 0; i < int(strs.size()); ++i) 13 | { 14 | int s0 = count(strs[i], '0'); 15 | int s1 = count(strs[i], '1'); 16 | for (int j = m; j >= s0; --j) 17 | for (int k = n; k >= s1; --k) 18 | dp[j][k] = max(dp[j][k], 1 + dp[j - s0][k - s1]); 19 | } 20 | return dp[m][n]; 21 | } 22 | 23 | int count(string str, char ch) 24 | { 25 | int cnt = 0; 26 | for (int i = 0; i < int(str.size()); ++i) 27 | if (str[i] == ch) 28 | cnt++; 29 | return cnt; 30 | } 31 | }; 32 | 33 | int main() 34 | { 35 | 36 | vector strs{ "10", "0", "1" }; 37 | int m = 1; 38 | int n = 1; 39 | Solution f; 40 | cout << f.findMaxForm(strs, m, n) << endl; 41 | 42 | getchar(); 43 | } -------------------------------------------------------------------------------- /LeetCode/48-旋转图像/method.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/LeetCode/48-旋转图像/method.jpg -------------------------------------------------------------------------------- /LeetCode/48-旋转图像/rotate.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/rotate-image 3 | 4 | 给定一个 n × n 的二维矩阵表示一个图像。 5 | 将图像顺时针旋转 90 度。 6 | 7 | 说明: 8 | 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。 9 | 10 | 给定 matrix = 11 | [ 12 | [ 5, 1, 9,11], 13 | [ 2, 4, 8,10], 14 | [13, 3, 6, 7], 15 | [15,14,12,16] 16 | ], 17 | 18 | 原地旋转输入矩阵,使其变为: 19 | [ 20 | [15,13, 2, 5], 21 | [14, 3, 4, 1], 22 | [12, 6, 8, 9], 23 | [16, 7,10,11] 24 | ] 25 | 26 | """ 27 | from typing import List 28 | 29 | 30 | class Solution: 31 | def rotate(self, matrix: List[List[int]]) -> None: 32 | """ 33 | 提示: 34 | 对坐标 (i, j) 可以找到旋转 90 度后的新坐标为 (j, cols-i),记之为 (i, j)->(j, cols-i), 35 | 那么,可以找到新坐标处的元素旋转后的新坐标。 36 | (i, j)->(j, cols-i)->(cols-i, cols-j)->(cols-j, i)->(i, j) 37 | 图示过程见本目录下 method.jpg。 38 | 39 | Do not return anything, modify matrix in-place instead. 40 | """ 41 | cols = len(matrix[0]) - 1 42 | for i in range(cols): 43 | for j in range(i, cols - i): 44 | tmp = [matrix[i][j], matrix[j][cols - i], matrix[cols - i][cols - j], matrix[cols - j][i]] 45 | matrix[j][cols - i] = tmp[0] 46 | matrix[cols - i][cols - j] = tmp[1] 47 | matrix[cols - j][i] = tmp[2] 48 | matrix[i][j] = tmp[3] -------------------------------------------------------------------------------- /LeetCode/494-目标和/leetcode494.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findTargetSumWays(vector& nums, int S) { 4 | if (nums.empty() || sum(nums) < S || (sum(nums) + S) % 2) 5 | return 0; 6 | int P = (sum(nums) + S) / 2; 7 | 8 | vector dp(P + 1, 0); 9 | dp[0] = 1; 10 | for (int i = 0; i < nums.size(); ++i) 11 | for (int j = P; j >= nums[i]; --j) 12 | dp[j] = dp[j - nums[i]] + dp[j]; 13 | return dp[P]; 14 | } 15 | 16 | int sum(vector nums) 17 | { 18 | int s = 0; 19 | for (int i = 0; i < nums.size(); ++i) 20 | s += nums[i]; 21 | return s; 22 | } 23 | }; -------------------------------------------------------------------------------- /LeetCode/5-最长回文子串/mian5.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string longestPalindrome(string s) { 4 | int size = s.size(); 5 | if (size <= 1) 6 | return s; 7 | int dp[size][size] = {false}; 8 | int longest_len = 1, cur_len = 0; 9 | int left = 0; 10 | 11 | for (int r = 1; r < size; ++r) 12 | for (int l = 0; l < r; ++l) 13 | if ((s[l] == s[r]) && (r - l <= 2 || dp[l+1][r-1])) 14 | { 15 | dp[l][r] = true; 16 | cur_len = r -l + 1; 17 | if (cur_len > longest_len) 18 | { 19 | longest_len = cur_len; 20 | left = l; 21 | } 22 | } 23 | return s.substr(left, longest_len); 24 | } 25 | }; -------------------------------------------------------------------------------- /LeetCode/55-跳跃游戏/jump.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/jump-game 3 | https://leetcode-cn.com/problems/jump-game/solution/pythonji-bai-97kan-bu-dong-ni-chui-wo-by-mo-lan-4/ 4 | 5 | 给定一个非负整数数组,你最初位于数组的第一个位置。 6 | 数组中的每个元素代表你在该位置可以跳跃的最大长度。 7 | 判断你是否能够到达最后一个位置。 8 | 9 | 示例 1: 10 | 输入: [2,3,1,1,4] 11 | 输出: true 12 | 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 13 | 14 | 示例 2: 15 | 输入: [3,2,1,0,4] 16 | 输出: false 17 | 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 18 | """ 19 | 20 | 21 | class Solution: 22 | def canJump(self, nums): 23 | """ 24 | 思路: 25 | 尽可能到达最远位置(贪心)。如果能到达某个位置,那一定能到达它前面的所有位置。 26 | 初始化最远位置为 0,然后遍历数组,如果当前位置能到达, 27 | 并且当前位置 + 当前位置能够跳跃的最大长度 > 最远位置,就更新最远位置。最后比较最远位置和数组长度。 28 | """ 29 | distance = 0 # 初始化当前能到达最远的位置 30 | for i, jump in enumerate(nums): # i 为当前位置,jump 是当前位置能够跳跃的最大长度 31 | if i <= distance < i + jump: # 如果当前位置能到达,并且当前位置 + 当前位置能够跳跃的最大长度 > 最远位置 32 | distance = i + jump # 更新最远能到达的位置 33 | return distance >= i 34 | -------------------------------------------------------------------------------- /LeetCode/55-跳跃游戏/leetcode55.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | /* 10 | https://leetcode-cn.com/problems/jump-game 11 | https://leetcode-cn.com/problems/jump-game/solution/pythonji-bai-97kan-bu-dong-ni-chui-wo-by-mo-lan-4/ 12 | 13 | 给定一个非负整数数组,你最初位于数组的第一个位置。 14 | 数组中的每个元素代表你在该位置可以跳跃的最大长度。 15 | 判断你是否能够到达最后一个位置。 16 | 17 | 示例 1: 18 | 输入: [2,3,1,1,4] 19 | 输出: true 20 | 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 21 | 22 | 示例 2: 23 | 输入: [3,2,1,0,4] 24 | 输出: false 25 | 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 26 | 27 | */ 28 | 29 | class Solution { 30 | public: 31 | bool canJump(vector& nums) { 32 | /* 33 | 思路: 34 | 尽可能到达最远位置(贪心)。如果能到达某个位置,那一定能到达它前面的所有位置。 35 | 初始化最远位置为 0,然后遍历数组,如果当前位置能到达, 36 | 并且当前位置 + 当前位置能够跳跃的最大长度 > 最远位置,就更新最远位置。最后比较最远位置和数组长度。 37 | */ 38 | int distance = 0; // 初始化当前能到达最远的位置 39 | for (int i = 0; i < nums.size(); ++i) 40 | if (i <= distance && distance < i + nums[i]) // 如果当前位置能到达,并且当前位置 + 当前位置能够跳跃的最大长度 > 最远位置 41 | distance = i + nums[i]; // 更新最远能到达的位置 42 | return distance >= nums.size() - 1; 43 | } 44 | }; 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /LeetCode/62-不同路径/leetcode62.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | https://leetcode-cn.com/problems/unique-paths 3 | 4 | 一个机器人位于一个 m x n 网格的左上角,机器人每次只能向下或者向右移动一步。 5 | 机器人试图达到网格的右下角,问总共有多少条不同的路径? 6 | 7 | 示例 1: 8 | 输入: m = 3, n = 2 9 | 输出: 3 10 | 解释: 11 | 从左上角开始,总共有 3 条路径可以到达右下角。 12 | 1. 向右 -> 向下 -> 向下 13 | 2. 向下 -> 向右 -> 向下 14 | 3. 向下 -> 向下 -> 向右 15 | 16 | 示例 2: 17 | 输入: m = 7, n = 3 18 | 输出: 28 19 | 20 | */ 21 | 22 | class Solution { 23 | public: 24 | int uniquePaths(int m, int n) { 25 | /* 26 | 提示:动态规划求解 27 | 令 dp[(i, j)] 是从左上角 (0, 0) 到达 (i, j) 的不同路径数量, 28 | 状态转移方程为:dp[(i, j)] = dp[(i-1, j)] + dp[(i, j-1)] 29 | 注意,对于索引为零的行 dp[(0, j)],或者索引为零的列 dp[i][0],由于都是在边界,所以只有一种到达方式。 30 | */ 31 | if (m <= 0 || n <= 0) 32 | return 0; 33 | 34 | int dp[m][n] = {0}; 35 | dp[0][0] = 1; // 从左上角到左上角只有 1 种走法,就是不走 36 | for (int i = 0; i < m; ++i) // 边界索引为 0 的列都只有一种到达方式 37 | dp[i][0] = 1; 38 | for (int j = 0; j < n; ++j) // 边界索引为 0 的行都只有一种到达方式 39 | dp[0][j] = 1; 40 | 41 | for (int i = 1; i < m; ++i) 42 | for (int j = 1; j < n; ++j) 43 | dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; 44 | return dp[m - 1][n - 1]; 45 | } 46 | }; -------------------------------------------------------------------------------- /LeetCode/62-不同路径/uniquePaths.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/unique-paths 4 | 5 | 一个机器人位于一个 m x n 网格的左上角,机器人每次只能向下或者向右移动一步。 6 | 机器人试图达到网格的右下角,问总共有多少条不同的路径? 7 | 8 | 示例 1: 9 | 输入: m = 3, n = 2 10 | 输出: 3 11 | 解释: 12 | 从左上角开始,总共有 3 条路径可以到达右下角。 13 | 1. 向右 -> 向下 -> 向下 14 | 2. 向下 -> 向右 -> 向下 15 | 3. 向下 -> 向下 -> 向右 16 | 17 | 示例 2: 18 | 输入: m = 7, n = 3 19 | 输出: 28 20 | 21 | """ 22 | 23 | 24 | class Solution: 25 | def __init__(self): 26 | self.dp = {(0, 0): 1} 27 | 28 | def uniquePaths(self, m: int, n: int) -> int: 29 | """ 30 | 提示:动态规划求解 31 | 令 dp[(i, j)] 是从左上角 (0, 0) 到达 (i, j) 的不同路径数量, 32 | 状态转移方程为:dp[(i, j)] = dp[(i-1, j)] + dp[(i, j-1)] 33 | 注意,对于索引为零的行 dp[(0, j)],或者索引为零的列 dp[i][0],由于都是在边界,所以只有一种到达方式。 34 | """ 35 | if m <= 0 or n <= 0: 36 | return 0 37 | # 第 0 行和第 0 列所在的格子,到达的方式只有一种。 38 | self.dp.update({(0, j): 1 for j in range(1, n)}) 39 | self.dp.update({(i, 0): 1 for i in range(1, m)}) 40 | # 从格子 (1, 1) 开始 41 | for i in range(1, m): 42 | for j in range(1, n): 43 | self.dp[(i, j)] = self.dp[(i - 1, j)] + self.dp[(i, j - 1)] 44 | return self.dp[(m - 1, n - 1)] 45 | 46 | 47 | if __name__ == "__main__": 48 | f = Solution() 49 | m, n = 7, 3 50 | print(f.uniquePaths(m, n)) 51 | -------------------------------------------------------------------------------- /LeetCode/64-最小路径和/leetcode64.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int minPathSum(vector>& grid) { 4 | if (grid.empty()) 5 | return 0; 6 | int m = grid.size(); 7 | int n = grid[0].size(); 8 | int dp[m][n] = {0}; 9 | // 处理边界 10 | dp[0][0] = grid[0][0]; 11 | for (int i = 1; i < m; ++i) // 处理索引为 0 的列 12 | dp[i][0] = dp[i - 1][0] + grid[i][0]; 13 | for (int j = 1; j < n; ++j) // 处理索引为 0 的行 14 | dp[0][j] = dp[0][j - 1] + grid[0][j]; 15 | for (int i = 1; i < m; ++i) 16 | for (int j = 1; j < n; ++j) 17 | dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; 18 | return dp[m - 1][n - 1]; 19 | } 20 | }; -------------------------------------------------------------------------------- /LeetCode/64-最小路径和/minPathSum.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/minimum-path-sum 4 | 5 | 给定一个包含非负整数的 m x n 网格, 6 | 请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 7 | 说明:每次只能向下或者向右移动一步。 8 | 9 | 示例: 10 | 输入: 11 | [[1,3,1], 12 | [1,5,1], 13 | [4,2,1]] 14 | 15 | 输出: 7 16 | 解释: 因为路径 1→3→1→1→1 的总和最小。 17 | 18 | """ 19 | from typing import List 20 | 21 | 22 | class Solution: 23 | def minPathSum(self, grid: List[List[int]]) -> int: 24 | """ 25 | 提示: 26 | 令 dp[i][j] 为从 grid[0][0] 到 grid[i][j] 路径上的数字总和最小的值。 27 | 则状态转移方程为: 28 | dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] if i > 0 and j > 0 29 | 30 | """ 31 | m = len(grid) 32 | n = len(grid[0]) 33 | dp = [[0] * n for _ in range(m)] 34 | dp[0][0] = grid[0][0] 35 | # 设置边界 36 | for i in range(1, m): 37 | dp[i][0] = dp[i-1][0] + grid[i][0] 38 | for i in range(1, n): 39 | dp[0][i] = dp[0][i-1] + grid[0][i] 40 | for i in range(1, m): 41 | for j in range(1, n): 42 | dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] 43 | return dp[-1][-1] -------------------------------------------------------------------------------- /LeetCode/65-有效数字/FSM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/LeetCode/65-有效数字/FSM.png -------------------------------------------------------------------------------- /LeetCode/66-加一/main66.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector plusOne(vector& digits) { 4 | int carry = 1; 5 | vector::iterator it = digits.end() - 1; 6 | vector::iterator start = digits.begin(); 7 | for (; it != start - 1; --it) { 8 | *it += carry; 9 | carry = 0; 10 | if (*it >= 10) { 11 | *it %= 10; 12 | carry = 1; 13 | if (it == start) 14 | digits.insert(start, carry); 15 | } 16 | } 17 | return digits; 18 | } 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /LeetCode/66-加一/plusOne.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode-cn.com/problems/plus-one 3 | 4 | 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 5 | 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 6 | 你可以假设除了整数 0 之外,这个整数不会以零开头。 7 | 8 | 示例 1: 9 | 输入: [1,2,3] 10 | 输出: [1,2,4] 11 | 解释: 输入数组表示数字 123。 12 | 13 | 示例 2: 14 | 输入: [4,3,2,1] 15 | 输出: [4,3,2,2] 16 | 解释: 输入数组表示数字 4321。 17 | 18 | """ 19 | from typing import List 20 | 21 | 22 | class Solution: 23 | def plusOne(self, digits: List[int]) -> List[int]: 24 | """ 25 | 提示:模拟进位 26 | """ 27 | carry = 1 # 把加以理解为进位 28 | for i in range(len(digits) - 1, -1, -1): 29 | digits[i] += carry 30 | carry = 0 31 | if digits[i] >= 10: 32 | digits[i] %= 10 33 | carry = 1 34 | if i == 0: 35 | digits.insert(0, carry) 36 | return digits 37 | -------------------------------------------------------------------------------- /LeetCode/69-x的平方根/mySqrt.py: -------------------------------------------------------------------------------- 1 | # -*- coding:itf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/sqrtx/ 4 | 5 | 实现 int sqrt(intx) 函数。 6 | 计算并返回 x 的平方根,其中 x 是非负整数。 7 | 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 8 | 9 | 示例 10 | 输入: 4 11 | 输出: 2 12 | 13 | 输入: 8 14 | 输出: 2 15 | 说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。 16 | """ 17 | 18 | class Solution(object): 19 | def mySqrt(self, x): 20 | """ 21 | 提示: 22 | 二分查找 23 | """ 24 | if x < 2: 25 | return x 26 | 27 | left, right = 1, x // 2 28 | while left <= right: 29 | mid = (left + right) // 2 30 | if mid * mid > x: 31 | right = mid - 1 32 | else: 33 | left = mid + 1 34 | return left - 1 35 | -------------------------------------------------------------------------------- /LeetCode/75-颜色排序/main75.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void sortColors(vector& nums) { 4 | int left = 0, right = nums.size() - 1; 5 | int i = 0; 6 | while (i <= right) 7 | { 8 | if (nums[i] == 2) 9 | { 10 | swap(nums[i], nums[right]); 11 | right--; 12 | } 13 | else if (nums[i] == 0) 14 | { 15 | swap(nums[i], nums[left]); 16 | left++; 17 | i++; 18 | } 19 | else 20 | i++; 21 | } 22 | } 23 | 24 | void swap(int &x, int &y) 25 | { 26 | int t = x; 27 | x = y; 28 | y = t; 29 | } 30 | 31 | // 如果使用 swap2,对测试用例 [2],不可行。 32 | // 因为 nums 只含有一个元素,此时 num[i] 与 num[right] 的地址相同, 33 | // 即 x, y 地址相同,此时改变了 x 也同时改变了 y,只能像上面的函数 swap 增加一个临时变量 t 以实现交换的功能。 34 | void swap2(int &x, int &y) 35 | { 36 | x = x ^ y; 37 | y = x ^ y; 38 | x = x ^ y; 39 | } 40 | }; -------------------------------------------------------------------------------- /LeetCode/75-颜色排序/sortColors.py: -------------------------------------------------------------------------------- 1 | # -*- coding:itf-8 -*- 2 | """ 3 | https://leetcode-cn.com/problems/sort-colors/ 4 | 5 | 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 6 | 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 7 | 注意: 8 | 不能使用代码库中的排序函数来解决这道题。 9 | 10 | 示例: 11 | 输入: [2,0,2,1,1,0] 12 | 输出: [0,0,1,1,2,2] 13 | 14 | """ 15 | 16 | 17 | class Solution(object): 18 | def sortColors(self, nums): 19 | """ 20 | 提示: 21 | 三路快排,0移动到最左边,2移动到最右边,遇到1则跳过。 22 | 23 | :type nums: List[int] 24 | :rtype: None Do not return anything, modify nums in-place instead. 25 | """ 26 | left = 0 # nums[:left] 已经排好了,都是0 27 | right = len(nums) - 1 # num[right + 1:] 已经排好了,都为2 28 | i = 0 29 | while i <= right: 30 | if nums[i] == 2: 31 | nums[i], nums[right] = nums[right], nums[i] 32 | right -= 1 33 | elif nums[i] == 0: 34 | nums[i], nums[left] = nums[left], nums[i] 35 | left += 1 36 | i += 1 37 | else: 38 | i += 1 -------------------------------------------------------------------------------- /LeetCode/876-链表的中间结点/leetcode876.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | https://leetcode-cn.com/problems/middle-of-the-linked-list 3 | 4 | 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。 5 | 如果有两个中间结点,则返回第二个中间结点。 6 | 7 | 示例 1: 8 | 输入:[1,2,3,4,5] 9 | 输出:此列表中的结点 3 (序列化形式:[3,4,5]) 10 | 返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。 11 | 注意,我们返回了一个 ListNode 类型的对象 ans,这样: 12 | ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL. 13 | 14 | 示例 2: 15 | 输入:[1,2,3,4,5,6] 16 | 输出:此列表中的结点 4 (序列化形式:[4,5,6]) 17 | 由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。 18 | 19 | */ 20 | 21 | /** 22 | * Definition for singly-linked list. 23 | * struct ListNode { 24 | * int val; 25 | * ListNode *next; 26 | * ListNode(int x) : val(x), next(NULL) {} 27 | * }; 28 | */ 29 | 30 | class Solution { 31 | public: 32 | ListNode* middleNode(ListNode* head) { 33 | /* 34 | 提示: 35 | 快慢指针: 36 | 快指针每次走两步,慢指针每次走一步,快指针到达链表尾部,慢指针刚好在中间结点 37 | */ 38 | ListNode* pFast = head; 39 | ListNode* pSlow = head; 40 | while (pFast != nullptr && pFast->next != nullptr) 41 | { 42 | pSlow = pSlow->next; 43 | pFast = pFast->next->next; 44 | } 45 | return pSlow; 46 | } 47 | }; 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /LeetCode/876-链表的中间结点/leetcode876.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/LeetCode/876-链表的中间结点/leetcode876.py -------------------------------------------------------------------------------- /LintCode/1-01背包无价值/backPack.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://www.lintcode.com/problem/backpack/description 4 | https://blog.csdn.net/u013166817/article/details/85449218 5 | 6 | 在 n个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为 m,每个物品的大小为 A[i]。 7 | 你不可以将物品进行切割。 8 | 9 | 样例 1: 10 | 输入: [3,4,8,5], backpack m = 10 11 | 输出: 9 12 | 13 | 样例 2: 14 | 输入: [2,3,5,7], backpack m = 12 15 | 输出: 12 16 | 17 | """ 18 | 19 | class Solution: 20 | """ 21 | @param m: An integer m denotes the n of a backpack 22 | @param A: Given n items with n A[i] 23 | @return: The maximum n 24 | """ 25 | 26 | def backPack(self, m, A): 27 | """ 28 | 提示: 29 | dp[i][j]:前 i 个物品(不包括 i)放入容量为 j 的背包的最大重量; 30 | dp[i-1][j-A[i]] + A[i]:放入第 i 个物品时的重量; 31 | dp[i-1][j]:不放第 i 个物品时的重量; 32 | 33 | 在遇到第 i 个物品时,需要考虑该物品是放入还是不放入 34 | 状态转移方程为: 35 | dp[i][j] = max(dp[i-1][j-A[i]] + A[i], dp[i-1][j]) 36 | 37 | 第一层循环 i:0 ~ n 38 | 第二层循环 j:m ~ A[i],倒序是因为每个物品只能用一次。 39 | 40 | 可简化成一维,令 dp[j] 为容量 j 的背包,装起物品的最大重量。 41 | dp[j] = max(dp[j - A[i]] + A[i], dp[j]) 42 | 43 | """ 44 | # write your code here 45 | n = len(A) 46 | if n <= 0 or m <= 0: 47 | return 0 48 | dp = [0 for _ in range(m + 1)] 49 | for i in range(n): 50 | for j in range(m, A[i] - 1, -1): # 每个物品只能用一次 51 | dp[j] = max(dp[j - A[i]] + A[i], dp[j]) 52 | return dp[-1] 53 | 54 | 55 | -------------------------------------------------------------------------------- /LintCode/1-01背包无价值/lintcode92.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 在 n个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为 m,每个物品的大小为 A[i]。 3 | 你不可以将物品进行切割。 4 | 5 | 样例 1: 6 | 输入: [3,4,8,5], backpack m=10 7 | 输出: 9 8 | 9 | 样例 2: 10 | 输入: [2,3,5,7], backpack m=12 11 | 输出: 12 12 | */ 13 | 14 | class Solution 15 | { 16 | public: 17 | /** 18 | * @param m: An integer m denotes the size of a backpack 19 | * @param A: Given n items with size A[i] 20 | * @return: The maximum size 21 | */ 22 | int backPack(int m, vector &A) 23 | { 24 | /** 25 | 提示: 26 | dp[i][j]:前 i 个物品(不包括 i)放入容量为 j 的背包的最大重量; 27 | dp[i-1][j-A[i]] + A[i]:放入第 i 个物品时的重量; 28 | dp[i-1][j]:不放第 i 个物品时的重量; 29 | 30 | 在遇到第 i 个物品时,需要考虑该物品是放入还是不放入 31 | 状态转移方程为: 32 | dp[i][j] = max(dp[i-1][j-A[i]] + A[i], dp[i-1][j]) 33 | 34 | 第一层循环 i:0 ~ n 35 | 第二层循环 j:m ~ A[i],倒序是因为每个物品只能用一次。 36 | 37 | 可简化成一维,令 dp[j] 为容量 j 的背包,装起物品的最大重量。 38 | dp[j] = max(dp[j - A[i]] + A[i], dp[j]) 39 | */ 40 | // write your code here 41 | int n = A.size(); 42 | if (n <= 0 || m <= 0) 43 | return 0; 44 | vector dp(m + 1, 0); 45 | for (int i = 0; i < n; ++i) 46 | for (int j = m; j >= A[i]; --j) // 01 背包,所以以容量的 for 循环 j 是从大到小递增 47 | dp[j] = max(dp[j - A[i]] + A[i], dp[j]); 48 | //dp[j] = dp[j - A[i]] + A[i] > dp[j] ? dp[j - A[i]] + A[i] : dp[j]; 49 | return dp[m]; 50 | } 51 | }; -------------------------------------------------------------------------------- /LintCode/2-01背包有价值/lintcode125.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值. 3 | 装入背包的物品总价值最大是多大? 4 | 5 | 样例 1: 6 | 输入: m = 10, A = [2, 3, 5, 7], V = [1, 5, 2, 4] 7 | 输出: 9 8 | 解释: 装入 A[1] 和 A[3] 可以得到最大价值, V[1] + V[3] = 9 9 | 10 | 样例 2: 11 | 输入: m = 10, A = [2, 3, 8], V = [2, 5, 8] 12 | 输出: 10 13 | 解释: 装入 A[0] 和 A[2] 可以得到最大价值, V[0] + V[2] = 10 14 | 15 | 注意事项 16 | A[i], V[i], n, m 均为整数 17 | 你不能将物品进行切分 18 | 你所挑选的要装入背包的物品的总大小不能超过 m 19 | 每个物品只能取一次 20 | */ 21 | 22 | class Solution 23 | { 24 | public: 25 | /** 26 | * @param m: An integer m denotes the size of a backpack 27 | * @param A: Given n items with size A[i] 28 | * @param V: Given n items with value V[i] 29 | * @return: The maximum value 30 | */ 31 | int backPackII(int m, vector &A, vector &V) 32 | { 33 | // write your code here 34 | int n = A.size(); 35 | if (m <= 0 || A.empty() || V.empty()) 36 | return 0; 37 | vector dp(m + 1, 0); 38 | for (int i = 0; i < n; ++i) 39 | for (int j = m; j >= A[i]; --j) // 01 背包,所以以容量的 for 循环 j 是从大到小递增 40 | dp[j] = max(dp[j], dp[j - A[i]] + V[i]); 41 | return dp[m]; 42 | } 43 | }; -------------------------------------------------------------------------------- /LintCode/3-完全背包/backPage.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 给定 n 种尺寸为 A[i] 且值为 V[i] 的物品(每件物品都有无限数量)和尺寸为 m 的背包。 4 | 装入背包的物品总价值最大是多大? 5 | 6 | 例: 7 | 给出 4 个尺寸为 [2,3,5,7] 且值为 [1,5,2,4] 的物品, 8 | 以及尺寸为 10 的背包。 9 | 背包内物品最大值为 15,即选三个价值为 5 的物品。 10 | 11 | """ 12 | 13 | 14 | class Solution: 15 | """ 16 | @param A: an integer array 17 | @param V: an integer array 18 | @param m: An integer 19 | @return: an array 20 | """ 21 | def backPackIII(self, A, V, m): 22 | """​​ 23 | dp[i][j]:前 i 个物品放入容量为 j 的背包的最大价值; 24 | dp[i][j-A[i]] + V[i]:放入第 i个物品时,不管上一次放没放入过该物品; 25 | dp[i-1][j]:不放入第 i 个物品时的价值; 26 | 27 | 在遇到第 i 个物品时,需要考虑该物品是放入还是不放入 28 | 状态转移方程为: 29 | dp[i][j] = max(dp[i][j-A[i]] + V[i], dp[i-1][j]) 30 | 31 | 可简化成一维,令 dp[j] 为容量 j 的背包,装起物品的最大重量。 32 | dp[j] = max(dp[j-A[i]] + V[i], dp[j]) 33 | 34 | """ 35 | # write your code here 36 | n = len(A) 37 | if n <= 0 or m <= 0: 38 | return 0 39 | dp = [0 for _ in range(m + 1)] 40 | for i in range(n): 41 | for j in range(A[i], m + 1): 42 | dp[j] = max(dp[j-A[i]] + V[i], dp[j]) 43 | return dp[-1] -------------------------------------------------------------------------------- /LintCode/3-完全背包/lintcode-x.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | /* 8 | 给定 n 种尺寸为 A[i] 且值为 V[i] 的物品(每件物品都有无限数量)和尺寸为 m 的背包。 9 | 装入背包的物品总价值最大是多大? 10 | 11 | 例: 12 | 给出 4 个尺寸为 [2,3,5,7] 且值为 [1,5,2,4] 的物品, 13 | 以及尺寸为 10 的背包。 14 | 背包内物品最大值为 15,即选三个价值为 5 的物品。 15 | */ 16 | 17 | int backPackIII(vector A, vector V, int m) 18 | { 19 | /* 20 | dp[i][j]:前 i 个物品放入容量为 j 的背包的最大价值; 21 | dp[i][j-A[i]] + V[i]:放入第 i个物品时,不管上一次放没放入过该物品; 22 | dp[i-1][j]:不放入第 i 个物品时的价值; 23 | 24 | 在遇到第 i 个物品时,需要考虑该物品是放入还是不放入 25 | 状态转移方程为: 26 | dp[i][j] = max(dp[i][j-A[i]] + V[i], dp[i-1][j]) 27 | 28 | 可简化成一维,令 dp[j] 为容量 j 的背包,装起物品的最大重量。 29 | dp[j] = max(dp[j-A[i]] + V[i], dp[j]) 30 | */ 31 | if (m <= 0 || A.empty() || V.empty()) 32 | return 0; 33 | vector dp(m + 1, 0); 34 | for (int i = 0; i < A.size(); ++i) 35 | for (int j = A[i]; j <= m; ++j) // 完全背包,所以以容量的 for 循环 j 是从小到大递增 36 | dp[j] = max(dp[j - A[i]] + V[i], dp[j]); 37 | return dp[m]; 38 | } 39 | 40 | int main() 41 | { 42 | vector A{2, 3, 5, 7}; 43 | vector V{1, 5, 2, 4}; 44 | int m = 10; 45 | cout << backPackIII(A, V, m) << endl; 46 | 47 | getchar(); 48 | } -------------------------------------------------------------------------------- /LintCode/4-01背包返回方案数/backPage.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 给定 n 个大小为 nums[i] 的物品,无重复。 4 | 整数 target 表示背包的大小。 5 | 在 nums 里挑选(不可重复挑选)一些物品,使其恰好能填充整个背包。 6 | 有多少种挑选方案? 7 | 8 | 例: 9 | 输入 nums = [2, 3, 6, 7],target 9, 10 | 11 | 输出 2。 12 | 解析: 13 | 共两种方案,[2, 7] 和 [3, 6] 14 | """ 15 | 16 | 17 | class Solution: 18 | """ 19 | @param nums: an integer array and all positive numbers, no duplicates 20 | @param target: An integer 21 | @return: An integere 22 | """ 23 | def backPackIV(self, nums, target): 24 | """ 25 | 提示: 26 | 令 dp[j] 为容量为 j 的背包的方案数。 27 | 当放入物品 nums[i],有方案数 dp[j - nums[i]]; 28 | 当不放入物品 nums[i],有方案数 dp[j]。 29 | 故总的方案数 dp[j] = dp[j - nums[i]] + dp[j] 30 | 31 | 【记忆】 32 | 将 01背包问题里面的 max 改为 sum,且初始化时将 dp[0] 设为 1; 33 | 因为背包容量为 0 时,只有一种放入方法:什么都不放。 34 | 35 | """ 36 | # write your code here 37 | n = len(nums) 38 | if n <= 0 or target < 0: 39 | return 0 40 | dp = [0 for _ in range(target + 1)] 41 | dp[0] = 1 42 | for i in range(n): 43 | for j in range(target, nums[i] - 1, -1): 44 | # dp[j] = sum([dp[j - nums[i]], dp[j]]) 45 | dp[j] = dp[j - nums[i]] + dp[j] 46 | return dp[-1] 47 | 48 | 49 | if __name__ == "__main__": 50 | nums = [2, 3, 6, 7] 51 | target = 9 52 | f = Solution() 53 | print(f.backPackIV(nums, target)) 54 | 55 | 56 | -------------------------------------------------------------------------------- /LintCode/4-01背包返回方案数/lintcode-x.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | /* 8 | 给定 n 个大小为 nums[i] 的物品,无重复。 9 | 整数 target 表示背包的大小。 10 | 在 nums 里挑选(不可重复挑选)一些物品,使其恰好能填充整个背包。 11 | 有多少种挑选方案? 12 | 13 | 例: 14 | 输入 nums = [2, 3, 6, 7],target 9, 15 | 16 | 输出 2。 17 | 解析: 18 | 共两种方案,[2, 7] 和 [3, 6] 19 | */ 20 | 21 | class Solution 22 | { 23 | public: 24 | int backPackIV(vector &nums, int target) 25 | { 26 | /* 27 | 提示: 28 | 令 dp[j] 为容量为 j 的背包的方案数。 29 | 当放入物品 nums[i],有方案数 dp[j - nums[i]]; 30 | 当不放入物品 nums[i],有方案数 dp[j]。 31 | 故总的方案数 dp[j] = dp[j - nums[i]] + dp[j] 32 | 33 | 【记忆】 34 | 将 01背包问题里面的 max 改为 sum,且初始化时将 dp[0] 设为 1; 35 | 因为背包容量为 0 时,只有一种放入方法:什么都不放。 36 | */ 37 | if (target <= 0 || nums.empty()) 38 | return 0; 39 | vector dp(target + 1, 0); 40 | dp[0] = 1; 41 | for (int i = 0; i < nums.size(); ++i) 42 | for (int j = target; j >= nums[i]; --j) 43 | dp[j] = dp[j - nums[i]] + dp[j]; 44 | return dp[target]; 45 | } 46 | }; 47 | 48 | int main() 49 | { 50 | vector nums{7, 3, 6, 2}; 51 | int target = 9; 52 | Solution f; 53 | cout << f.backPackIV(nums, target) << endl; 54 | 55 | getchar(); 56 | } -------------------------------------------------------------------------------- /LintCode/5-完全背包返回方案数/backPage.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 给定 n 个大小为 nums[i] 的物品,无重复。 4 | 整数 target 表示背包的大小。 5 | 在 nums 里挑选(可以重复挑选)一些物品,使其恰好能填充整个背包。 6 | 有多少种挑选方案? 7 | 8 | 例: 9 | 输入 nums = [2, 3, 6, 7],target 9, 10 | 11 | 输出 4。 12 | 解析: 13 | 共四种方案,[2, 2, 2, 3]、[3, 6]、[2, 7] 和 [3, 3, 3] 14 | """ 15 | 16 | 17 | class Solution: 18 | """ 19 | @param nums: an integer array and all positive numbers, no duplicates 20 | @param target: An integer 21 | @return: An integer 22 | """ 23 | def backPackIV(self, nums, target): 24 | """ 25 | 提示: 26 | 令 dp[j] 为容量为 j 的背包的方案数。 27 | 当放入物品 nums[i],有方案数 dp[j - nums[i]]; 28 | 当不放入物品 nums[i],有方案数 dp[j]。 29 | 故总的方案数 dp[j] = dp[j - nums[i]] + dp[j] 30 | 31 | 【记忆】 32 | 将完全背包问题里面的 max 改为 sum,且初始化时将 dp[0] 设为 1; 33 | 因为背包容量为 0 时,只有一种放入方法:什么都不放。 34 | 35 | """ 36 | # write your code here 37 | n = len(nums) 38 | if n <= 0 or target < 0: 39 | return 0 40 | dp = [0 for _ in range(target+1)] 41 | dp[0] = 1 42 | for i in range(n): 43 | for j in range(nums[i], target+1): 44 | # dp[j] = sum([dp[j - nums[i]], dp[j]]) 45 | dp[j] = dp[j - nums[i]] + dp[j] 46 | return dp[-1] 47 | 48 | 49 | if __name__ == "__main__": 50 | nums = [2, 3, 6, 7] 51 | target = 9 52 | f = Solution() 53 | print(f.backPackIV(nums, target)) 54 | 55 | 56 | -------------------------------------------------------------------------------- /LintCode/5-完全背包返回方案数/lintcode562.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 给定 n 个大小为 nums[i] 的物品,无重复。 3 | 整数 target 表示背包的大小。 4 | 在 nums 里挑选(可以重复挑选)一些物品,使其恰好能填充整个背包。 5 | 有多少种挑选方案? 6 | 7 | 例: 8 | 输入 nums = [2, 3, 6, 7],target 9, 9 | 10 | 输出 4。 11 | 解析: 12 | 共四种方案,[2, 2, 2, 3]、[3, 6]、[2, 7] 和 [3, 3, 3] 13 | */ 14 | 15 | class Solution 16 | { 17 | public: 18 | /** 19 | * @param nums: an integer array and all positive numbers, no duplicates 20 | * @param target: An integer 21 | * @return: An integer 22 | */ 23 | int backPackIV(vector &nums, int target) 24 | { 25 | /* 26 | 提示: 27 | 令 dp[j] 为容量为 j 的背包的方案数。 28 | 当放入物品 nums[i],有方案数 dp[j - nums[i]]; 29 | 当不放入物品 nums[i],有方案数 dp[j]。 30 | 故总的方案数 dp[j] = dp[j - nums[i]] + dp[j] 31 | 32 | 【记忆】 33 | 将完全背包问题里面的 max 改为 sum,且初始化时将 dp[0] 设为 1; 34 | 因为背包容量为 0 时,只有一种放入方法:什么都不放。 35 | */ 36 | // write your code here 37 | if (target <= 0 || nums.empty()) 38 | return 0; 39 | vector dp(target + 1, 0); 40 | dp[0] = 1; 41 | for (int i = 0; i < nums.size(); ++i) 42 | for (int j = nums[i]; j <= target; ++j) 43 | dp[j] = dp[j - nums[i]] + dp[j]; 44 | return dp[target]; 45 | } 46 | }; -------------------------------------------------------------------------------- /acmcoder/1-约德尔测试/yueDeErCeShi.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://exercise.acmcoder.com/online/online_judge_ques?ques_id=1677&konwledgeId=135 4 | 5 | 兰博和提莫闲聊之后,回归到了他们的正题,约德尔人的未来。说起约德尔人的未来,黑默丁格曾经提出了一个约德尔测试, 6 | 将约德尔人的历史的每个阶段都用一个字符表达出来。(包括可写字符,不包括空格。)。然后将这个字符串转化为一个01串。 7 | 转化规则是如果这个字符是字母或者数字,这个字符变为1,其它变为0。 8 | 然后将这个01串和黑默丁格观测星空得到的01串做比较,得到一个相似率。相似率越高,则约德尔的未来越光明。 9 | 请问:相似率为多少? 10 | 11 | 输入: 12 | 每组输入数据为两行,第一行为有关约德尔人历史的字符串,第二行是黑默丁格观测星空得到的字符串。 13 | (两个字符串的长度相等,字符串长度不小于1且不超过1000。) 14 | 15 | 输出: 16 | 输出一行,在这一行输出相似率。用百分数表示。 17 | (相似率为相同字符的个数/总个数,精确到百分号小数点后两位。) 18 | 19 | 样例输入: 20 | @!%12dgsa 21 | 010111100 22 | 23 | 样例输出: 24 | 66.67% 25 | """ 26 | 27 | 28 | class Solution: 29 | def process(self, history, star): 30 | cnt = 0 31 | record = list(map(self.translate, history)) 32 | for (x, y) in zip(record, star): 33 | if x == y: 34 | cnt += 1 35 | return cnt/len(star) 36 | 37 | def translate(self, ch): 38 | if ch.isalnum(): 39 | return '1' 40 | else: 41 | return '0' 42 | 43 | 44 | if __name__ == "__main__": 45 | i_history = input().strip() 46 | i_star = input().strip() 47 | f = Solution() 48 | result = f.process(i_history, i_star) 49 | print("%.2f%%" % (100 * result)) 50 | -------------------------------------------------------------------------------- /acmcoder/2-格子游戏/geZiYouXi.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | https://exercise.acmcoder.com/online/online_judge_ques?ques_id=1662&konwledgeId=135 4 | 5 | 有n个格子,从左到右放成一排,编号为1-n。 6 | 共有m次操作,有3种操作类型: 7 | 1.修改一个格子的权值, 8 | 2.求连续一段格子权值和, 9 | 3.求连续一段格子的最大值。 10 | 对于每个2、3操作输出你所求出的结果。 11 | 12 | 输入: 13 | 输入第一行两个整数,n表示格子个数,m表示操作次数,n和m中间用空格隔开; 14 | 接下来输入n行,每行一个整数表示一个格子的权值。 15 | 接下来输入m行,每行有三个整数,中间用空格隔开;第一个是选择的操作类型1-3,第二和第三个整数是操作格子的编号。 16 | 17 | 样例输入: 18 | 3 3 19 | 7 20 | 8 21 | 9 22 | 2 1 3 23 | 3 1 3 24 | 2 1 2 25 | 26 | 输出: 27 | 若执行1操作则无输出 28 | 若执行2和3操作则输出一个整数 29 | 30 | 样例输出: 31 | 24 32 | 9 33 | 15 34 | """ 35 | 36 | 37 | def opera(arr, op, var1, var2): 38 | if op == 1: 39 | pass 40 | # arr[var1] = var2 41 | elif op == 2: 42 | print(sum(arr[var1 - 1: var2])) 43 | elif op == 3: 44 | print(max(arr[var1 - 1: var2])) 45 | 46 | 47 | if __name__ == "__main__": 48 | n, m = list(map(int, input().strip().split())) 49 | L = [] 50 | for i in range(n): 51 | L.append(int(input().strip())) 52 | for i in range(m): 53 | ops = list(map(int, input().strip().split())) 54 | opera(L, *ops) 55 | 56 | 57 | -------------------------------------------------------------------------------- /dataStructure/assets/README/20200423161856.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/20200423161856.png -------------------------------------------------------------------------------- /dataStructure/assets/README/953680-20171102225031732-905731989.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/953680-20171102225031732-905731989.png -------------------------------------------------------------------------------- /dataStructure/assets/README/953680-20171102225105091-760301993.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/953680-20171102225105091-760301993.png -------------------------------------------------------------------------------- /dataStructure/assets/README/953680-20171102225137216-1323160728.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/953680-20171102225137216-1323160728.png -------------------------------------------------------------------------------- /dataStructure/assets/README/953680-20171102225214701-1271434709.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/953680-20171102225214701-1271434709.png -------------------------------------------------------------------------------- /dataStructure/assets/README/953680-20171102225258170-1980199509.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/953680-20171102225258170-1980199509.png -------------------------------------------------------------------------------- /dataStructure/assets/README/AVL_RL1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/AVL_RL1.png -------------------------------------------------------------------------------- /dataStructure/assets/README/AVL_RL2-1646061568338.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/AVL_RL2-1646061568338.png -------------------------------------------------------------------------------- /dataStructure/assets/README/AVL_RL2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/AVL_RL2.png -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-05246384c1c16537ca6176983bdb2627_b.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-05246384c1c16537ca6176983bdb2627_b.webp -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-2ddb0f9b832fff594e294dffc299b373_b.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-2ddb0f9b832fff594e294dffc299b373_b.webp -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-373766641d1c03a78f3d7eac803d1f57_b.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-373766641d1c03a78f3d7eac803d1f57_b.webp -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-37639b80cb65b60a531d3f5dc73dad52_720w.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-37639b80cb65b60a531d3f5dc73dad52_720w.jpg -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-41a3bdcb0c8b6478446c09ce22d14561_720w.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-41a3bdcb0c8b6478446c09ce22d14561_720w.jpg -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-db1cdb0da952a71f9b6d64b2608467eb_b.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-db1cdb0da952a71f9b6d64b2608467eb_b.webp -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-e60c01fa31634d9c63c63ecfb58036b2_720w.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-e60c01fa31634d9c63c63ecfb58036b2_720w.jpg -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-e7044e4965ba640ee9ef35beac407cdc_b-1646060200511.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-e7044e4965ba640ee9ef35beac407cdc_b-1646060200511.webp -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-e7044e4965ba640ee9ef35beac407cdc_b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-e7044e4965ba640ee9ef35beac407cdc_b.jpg -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-e7044e4965ba640ee9ef35beac407cdc_b.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-e7044e4965ba640ee9ef35beac407cdc_b.webp -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-f8e97ce8bff6af406ca2e3399be7ad5e_720w.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-f8e97ce8bff6af406ca2e3399be7ad5e_720w.jpg -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-f95f74ae3e76458d56ae3208bdde5987_720w.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-f95f74ae3e76458d56ae3208bdde5987_720w.jpg -------------------------------------------------------------------------------- /dataStructure/assets/README/v2-fd82c10388b933d1c09d1fbe297984ef_720w.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/assets/README/v2-fd82c10388b933d1c09d1fbe297984ef_720w.jpg -------------------------------------------------------------------------------- /dataStructure/list/doubleLinkedList.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | class Node(object): 3 | def __init__(self, item): 4 | # 元素域 5 | self.item = item 6 | # 链接域 7 | self.prior = None 8 | self.next = None 9 | 10 | 11 | class DoubleLinkedList(object): # 双向链表 12 | def __init__(self, node=None): 13 | self.head = node 14 | 15 | def __len__(self): # size 16 | # 游标 cursor ,用来遍历链表 17 | cur = self.head 18 | # 记录遍历次数 19 | count = 0 20 | # 当前节点为None则说明已经遍历完毕 21 | while cur: 22 | count += 1 23 | cur = cur.next 24 | return count 25 | 26 | """ 27 | 用时再补充 28 | """ 29 | 30 | if __name__ == "__main__": 31 | pass 32 | -------------------------------------------------------------------------------- /dataStructure/queue/deque.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | 4 | class Deque: 5 | def __init__(self): 6 | self.items = [] 7 | 8 | def addFront(self, item): # 首部添加元素 9 | self.items.append(item) 10 | 11 | def addRear(self, item): # 尾部添加元素 12 | self.items.insert(0, item) 13 | 14 | def removeFront(self): # 首部删除元素 15 | return self.items.pop() 16 | 17 | def removeRear(self): # 尾部删除元素 18 | return self.items.pop(0) 19 | 20 | def size(self): 21 | return len(self.items) 22 | 23 | def isEmpty(self): 24 | return self.items == [] 25 | 26 | def clear(self): 27 | del self.items[:] 28 | 29 | 30 | if __name__ == "__main__": 31 | d = Deque() 32 | d.addRear(5) 33 | d.addRear(6) 34 | d.addRear(7) 35 | d.addFront(8) 36 | d.addFront(9) 37 | d.addFront(10) 38 | print(d.items) 39 | d.removeFront() 40 | print(d.items) 41 | d.removeRear() 42 | print(d.items) 43 | d.clear() 44 | print(d.items) 45 | print(d.isEmpty()) 46 | 47 | 48 | -------------------------------------------------------------------------------- /dataStructure/queue/queue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/queue/queue.jpg -------------------------------------------------------------------------------- /dataStructure/queue/queue.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | 4 | class Queue: 5 | """先进先出""" 6 | def __init__(self): 7 | self.items = [] 8 | 9 | def enqueue(self, item): 10 | self.items.insert(0, item) 11 | 12 | def dequeue(self): 13 | return self.items.pop() 14 | 15 | def isEmpty(self): 16 | return self.items == [] 17 | 18 | def size(self): 19 | return len(self.items) 20 | 21 | def clear(self): # 设置为空队列 22 | del self.items[:] 23 | 24 | 25 | if __name__ == "__main__": 26 | q = Queue() 27 | q.enqueue(9) 28 | q.enqueue(8) 29 | q.enqueue(5) 30 | print(q.items) 31 | print(q.size()) 32 | print(q.isEmpty()) 33 | q.dequeue() 34 | print(q.items) 35 | print(q.size()) 36 | print(q.isEmpty()) 37 | q.clear() 38 | print(q.items) 39 | print(q.size()) 40 | print(q.isEmpty()) 41 | -------------------------------------------------------------------------------- /dataStructure/sort/bubble.cpp: -------------------------------------------------------------------------------- 1 | void bubble(int *arr, int len) 2 | { 3 | int t; 4 | for (int i = 0; i < len - 1; ++i) // 一共有 len - 1 轮 5 | for (int j = 0; j < len - i - 1; ++j) // 每轮有 len - i - 1 次比较 6 | if (arr[j] > arr[j + 1]) // 前面数字大于后面数字,就交换 7 | t = arr[j], arr[j] = arr[j + 1], arr[j + 1] = t; 8 | } -------------------------------------------------------------------------------- /dataStructure/sort/bubbleSort.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | class Sort: 4 | def bubbleSort(self, arr): 5 | # 需要 len(l)-1 次遍历 6 | for i in range(len(arr) - 1): 7 | # 第 i 次遍历,说明已经使 i 个大的数沉底,那么只需要对列表 arr[:len(arr)-i]部分相邻的元素比较大小 8 | # 且只需要比较 len(l)-i-1 次 9 | print(arr) 10 | # len(arr) - i 个元素,需要比较 len(arr) - i - 1 次 11 | for j in range(len(arr) - i - 1): 12 | if arr[j] > arr[j + 1]: 13 | arr[j], arr[j + 1] = arr[j + 1], arr[j] 14 | return arr 15 | 16 | 17 | if __name__ == "__main__": 18 | f = Sort() 19 | arr = [9, 8, 5, 6, 3] 20 | print("原始数组:{}\n排序过程:".format(arr)) 21 | print(f.bubbleSort(arr)) 22 | -------------------------------------------------------------------------------- /dataStructure/sort/insert.cpp: -------------------------------------------------------------------------------- 1 | void insert(int *arr, int len) 2 | { 3 | int i, j, t; 4 | for (i = 1; i < len; ++i) // 从第二个数开始(索引1),一共 len - 1 轮 5 | { 6 | t = arr[i]; 7 | for (j = i - 1; j >= 0 && t < arr[j]; --j) 8 | arr[j + 1] = arr[j]; 9 | arr[j + 1] = t; 10 | } 11 | } -------------------------------------------------------------------------------- /dataStructure/sort/insertSort.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | 4 | class Sort: 5 | def insertSort(self, arr): 6 | for i in range(1, len(arr)): # 需要 len(l)-1 轮插入才排序完毕 7 | t = arr[i] 8 | j = i - 1 9 | # 每一轮跟排序好的部分最多比较 i 次,而排序好的部分是 arr[:i] 10 | while j >= 0 and arr[j] > t: 11 | arr[j+1] = arr[j] # 前面一个数 arr[j] 大于 t,就把该数后移一位 12 | j -= 1 13 | arr[j+1] = t 14 | print(arr) 15 | return arr 16 | 17 | 18 | if __name__ == "__main__": 19 | arr = [9, 8, 5, 6, 3] 20 | f = Sort() 21 | print("原始数组:{}\n排序过程:".format(arr)) 22 | f.insertSort(arr) 23 | 24 | -------------------------------------------------------------------------------- /dataStructure/sort/makefile: -------------------------------------------------------------------------------- 1 | #OBJS = bubble.o insert.o merge.o quick.o select.o shell.o sort.o 2 | #OBJS = $(wildcard *.o) 3 | OBJS = $(patsubst %.cpp, %.o, $(wildcard *.cpp)) 4 | SRC = $(wildcard *.cpp) 5 | 6 | CC = g++ 7 | STD = -std=c++11 8 | 9 | sort:${OBJS} 10 | ${CC} ${OBJS} -o $@ ${STD} 11 | all:${SRC} 12 | ${CC} -c ${SRC} ${STD} 13 | clean: 14 | rm -f *.o sort 15 | -------------------------------------------------------------------------------- /dataStructure/sort/merge.cpp: -------------------------------------------------------------------------------- 1 | 2 | void mergeCore(int *arr, int low, int mid, int high) 3 | { 4 | int i, k; 5 | int *tmp = new int[high - low + 1]; 6 | // int *tmp = (int *)malloc((high - low + 1) * sizeof(int)); 7 | int left_low = low, left_high = mid; 8 | int right_low = mid + 1, right_high = high; 9 | for (k = 0; left_low <= left_high && right_low <= right_high; k++) 10 | if (arr[left_low] <= arr[right_low]) 11 | tmp[k] = arr[left_low++]; 12 | else 13 | tmp[k] = arr[right_low++]; 14 | if (left_low <= left_high) 15 | for (i = left_low; i <= left_high; i++) 16 | tmp[k++] = arr[i]; 17 | if (right_low <= right_high) 18 | for (i = right_low; i <= right_high; i++) 19 | tmp[k++] = arr[i]; 20 | for (i = 0; i < high - low + 1; i++) 21 | arr[low + i] = tmp[i]; 22 | delete[] tmp; 23 | // free(tmp); 24 | } 25 | 26 | void merge(int *arr, unsigned int first, unsigned int last) 27 | { 28 | int mid = 0; 29 | if (first < last) 30 | { 31 | mid = (first + last) / 2; 32 | merge(arr, first, mid); 33 | merge(arr, mid + 1, last); 34 | mergeCore(arr, first, mid, last); 35 | } 36 | } -------------------------------------------------------------------------------- /dataStructure/sort/mysort.h: -------------------------------------------------------------------------------- 1 | #ifndef MYSORT_H 2 | #define MYSORT_H 3 | 4 | void bubble(int *arr, int len); 5 | void insert(int *arr, int len); 6 | void merge(int *arr, unsigned int first, unsigned int last); 7 | void quick(int *arr, int start, int end); 8 | void select(int *arr, int len); 9 | void shell(int *arr,int len); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /dataStructure/sort/quick.cpp: -------------------------------------------------------------------------------- 1 | int partition(int *arr, int low, int high) 2 | { 3 | int key = arr[low]; // 默认第一个数作为基准 4 | while (low < high) 5 | { 6 | while (low < high && arr[high] >= key) 7 | high--; 8 | if (low < high) 9 | arr[low++] = arr[high]; 10 | while (low < high && arr[low] <= key) 11 | low++; 12 | if (low < high) 13 | arr[high--] = arr[low]; 14 | } 15 | arr[low] = key; 16 | return low; 17 | } 18 | 19 | void quick(int *arr, int start, int end) 20 | { 21 | int pos; 22 | if (start < end) 23 | { 24 | pos = partition(arr, start, end); 25 | quick(arr, start, pos - 1); 26 | quick(arr, pos + 1, end); 27 | } 28 | } -------------------------------------------------------------------------------- /dataStructure/sort/quickSort.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | 4 | class Sort: 5 | def quickSort(self, arr, start, end): 6 | if start < end: 7 | pos = self.partition(arr, start, end) 8 | self.quickSort(arr, start, pos - 1) 9 | self.quickSort(arr, pos + 1, end) 10 | 11 | def partition(self, arr, left, right): 12 | key = arr[left] 13 | print("left = {},right = {},key = {}".format(left, right, key)) 14 | while right > left: 15 | while right > left and arr[right] >= key: 16 | right -= 1 17 | if right > left: 18 | arr[left] = arr[right] # 把 right 处位置的元素赋值到 left 处,可以想象 right 处位置空出来了 19 | left += 1 20 | while right > left and arr[left] <= key: 21 | left += 1 22 | if right > left: 23 | arr[right] = arr[left] 24 | right -= 1 25 | # 每一步操作前都必须判断 right > left,因为每一步操作后都紧跟着改变了 left 或者 right. 26 | # 此时 right 与 left 指向数组同一个位置 27 | arr[left] = key 28 | print("partition 后 arr = {}".format(arr)) 29 | return left 30 | 31 | 32 | 33 | 34 | if __name__ == "__main__": 35 | arr = [3, 5, 7, 1, 9, 8, 5, 6, 2] 36 | print("原始数组:{}\n排序过程:".format(arr)) 37 | f = Sort() 38 | f.quickSort(arr, 0, len(arr) - 1) -------------------------------------------------------------------------------- /dataStructure/sort/radixSort.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/dataStructure/sort/radixSort.py -------------------------------------------------------------------------------- /dataStructure/sort/select.cpp: -------------------------------------------------------------------------------- 1 | void select(int *arr, int len) 2 | { 3 | int i, j, k, t; 4 | for (i = 0; i < len - 1; ++i) 5 | { 6 | k = i; 7 | for (j = i + 1; j < len; j++) 8 | if (arr[j] < arr[k]) // 把比 arr[k] 更小的值的索引赋给 k 9 | k = j; 10 | if (k != i) 11 | t = arr[i], arr[i] = arr[k], arr[k] = t; 12 | } 13 | } -------------------------------------------------------------------------------- /dataStructure/sort/selectSort.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import random 3 | 4 | class Sort: 5 | 6 | def selectSort(self, arr): 7 | for i in range(len(arr)): 8 | m = i 9 | for j in range(i + 1, len(arr)): 10 | if arr[m] > arr[j]: 11 | m = j 12 | if i != m: 13 | arr[i], arr[m] = arr[m], arr[i] 14 | print(arr) 15 | return arr 16 | 17 | def selectSort2(self, arr): # python 风格的递归实现 18 | if not arr: 19 | return arr 20 | m = min(arr) 21 | arr.remove(m) 22 | arr.insert(0, m) 23 | return arr[:1] + self.selectSort2(arr[1:]) 24 | 25 | 26 | if __name__ == "__main__": 27 | f = Sort() 28 | # arr = [random.randint(0, 99) for _ in range(10)] 29 | arr = [3, 5, 71, 7, 9, 8, 5, 6, 2] 30 | print("原始数组:{}\n排序过程:".format(arr)) 31 | f.selectSort(arr) 32 | 33 | print("\npython 风格的递归实现") 34 | arr = [3, 5, 71, 7, 9, 8, 5, 6, 2] 35 | print("原始数组:{}\n排序过程:".format(arr)) 36 | print(f.selectSort2(arr)) 37 | -------------------------------------------------------------------------------- /dataStructure/sort/shell.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | shell 排序是对插入排序的一个改进 3 | */ 4 | void shell(int *arr,int len) 5 | { 6 | int i, j, x, d; 7 | d = len/2; 8 | // 当增量 d 为 1 时,执行的就是插入排序。 9 | // 但实际上当 d = 1 时,此时数组很有序,只需要少量操作就可以排完序。 10 | while(d >= 1) 11 | { 12 | for(i = d; i < len; ++i) 13 | { 14 | x = arr[i]; 15 | j = i - d; 16 | while(j >= 0 && arr[j] > x) 17 | { 18 | arr[j + d] = arr[j]; 19 | j -= d; 20 | } 21 | arr[j + d] = x; 22 | } 23 | d /= 2; 24 | } 25 | } -------------------------------------------------------------------------------- /dataStructure/sort/shellSort.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | 4 | class Sort: 5 | def shellSort(self, arr): 6 | d = len(arr) // 2 7 | while d >= 1: 8 | # 当增量 d 为 1 时,执行的就是插入排序。 9 | # 但实际上当 d = 1 时,此时数组很有序,只需要少量操作就可以排完序。 10 | for i in range(d, len(arr)): 11 | t = arr[i] # 将要插入的元素 t 12 | j = i - d # 子序列中,t 前面的一个元素 13 | while j >= 0 and arr[j] > t: 14 | arr[j + d] = arr[j] 15 | j -= d 16 | arr[j + d] = t 17 | print(arr) 18 | d //= 2 19 | return arr 20 | 21 | 22 | if __name__ == "__main__": 23 | arr = [9, 8, 5, 6, 3, 5, 7, 1, 2] 24 | print("原始数组:{}\n排序过程:".format(arr)) 25 | f = Sort() 26 | f.shellSort(arr) -------------------------------------------------------------------------------- /dataStructure/stack/stack.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | 4 | class Stack: 5 | """先进后出""" 6 | def __init__(self): 7 | self.items = [] 8 | 9 | def push(self, item): # 压入 10 | self.items.append(item) 11 | 12 | def pop(self): # 弹出 13 | return self.items.pop() 14 | 15 | def isEmpty(self): # 判断栈是否为空 16 | return self.items == [] 17 | 18 | def size(self): 19 | return len(self.items) 20 | 21 | def peek(self): # 返回 stack 顶部元素,但不会修改 stack 22 | return self.items[-1] 23 | 24 | def clear(self): # 设置为空栈 25 | del self.items[:] 26 | 27 | 28 | if __name__ == "__main__": 29 | s = Stack() 30 | s.push(8) 31 | s.push(5) 32 | s.push(9) 33 | print(s.items) 34 | print(s.size()) 35 | print(s.pop()) 36 | print(s.items) 37 | print(s.isEmpty()) 38 | print(s.peek()) 39 | print(s.items) 40 | s.clear() 41 | print(s.items) 42 | print(s.isEmpty()) 43 | 44 | 45 | -------------------------------------------------------------------------------- /exercise/printThreadABC.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /** 9 | * @brief 题目 10 | * 三个线程交替打印 ABC 10 次 11 | */ 12 | 13 | std::mutex mtx; 14 | std::condition_variable cv; 15 | char ready = 0; 16 | 17 | void print_fun(char chId) 18 | { 19 | int cnt = 10; 20 | char ch = chId - 'A'; 21 | 22 | for (int i = 0; i < cnt; ++i) 23 | { 24 | std::unique_lock lk(mtx); 25 | cv.wait(lk, [ch] 26 | { return ch == ready; }); 27 | std::cout << std::this_thread::get_id() << ": " 28 | << (char)(ch + 'A') << std::endl; 29 | ready = (ch + 1) % 3; 30 | // lk.unlock(); 31 | 32 | cv.notify_all(); 33 | } 34 | } 35 | 36 | int main() 37 | { 38 | std::vector threads; 39 | threads.push_back(std::thread(print_fun, 'A')); 40 | threads.push_back(std::thread(print_fun, 'B')); 41 | threads.push_back(std::thread(print_fun, 'C')); 42 | 43 | std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join)); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /framework/safeMessageQueue/Dvr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DVR_HPP 2 | #define DVR_HPP 3 | 4 | #include "subject.hpp" 5 | #include "garbo.hpp" 6 | #include "../log.hpp" 7 | 8 | #include 9 | #include 10 | 11 | #define DVR_MAX (2) 12 | 13 | class Dvr final : public Subject 14 | { 15 | private: 16 | int mId; 17 | 18 | private: 19 | static std::mutex sMutex; 20 | static Dvr *sInstance[DVR_MAX]; 21 | 22 | protected: 23 | Dvr(); 24 | explicit Dvr(int id); 25 | Dvr(const Dvr &) = delete; 26 | Dvr &operator=(const Dvr &) = delete; 27 | virtual ~Dvr(); 28 | 29 | friend Garbo; 30 | 31 | public: // static function 32 | static Dvr *getInstance(const int id); 33 | static bool is_instance_exist(const int id); 34 | static int alloc_dvr_id(); 35 | 36 | void prepare(); 37 | void start(); 38 | void pause(); 39 | void restart(); 40 | void stop(); 41 | }; 42 | 43 | #endif -------------------------------------------------------------------------------- /framework/safeMessageQueue/Hdd.cpp: -------------------------------------------------------------------------------- 1 | #include "Hdd.hpp" 2 | #include "../log.hpp" 3 | #include 4 | 5 | std::mutex Hdd::sMutex; 6 | Hdd *Hdd::sInstance = nullptr; 7 | 8 | Hdd::Hdd() 9 | { 10 | std::thread check_space_thread(&Hdd::check_space, this); 11 | check_space_thread.detach(); 12 | } 13 | 14 | Hdd::~Hdd() 15 | { 16 | } 17 | 18 | Hdd *Hdd::getInstance() 19 | { 20 | login(); 21 | if (nullptr == sInstance) 22 | { 23 | std::lock_guard lock(sMutex); 24 | 25 | if (nullptr == sInstance) 26 | { 27 | logi("create Hdd"); 28 | sInstance = new Hdd(); 29 | } 30 | } 31 | 32 | return sInstance; 33 | } 34 | 35 | void Hdd::check_space() 36 | { 37 | while (true) 38 | { 39 | logi("Hdd check space"); 40 | std::this_thread::sleep_for(std::chrono::seconds(3)); 41 | } 42 | } -------------------------------------------------------------------------------- /framework/safeMessageQueue/Hdd.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HDD_HPP 2 | #define HDD_HPP 3 | 4 | #include "subject.hpp" 5 | 6 | #include 7 | #include 8 | 9 | class Hdd final : public Subject 10 | { 11 | private: 12 | static std::mutex sMutex; 13 | static Hdd *sInstance; 14 | 15 | protected: 16 | Hdd(); 17 | Hdd(const Hdd &) = delete; 18 | Hdd &operator=(const Hdd &) = delete; 19 | virtual ~Hdd(); 20 | 21 | public: 22 | static Hdd *getInstance(); 23 | 24 | void check_space(); 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /framework/safeMessageQueue/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ -g -Wall *.cpp -o main -pthread 3 | 4 | clean: 5 | rm main 6 | -------------------------------------------------------------------------------- /framework/safeMessageQueue/ModuleManager.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_MANAGER_HPP 2 | #define MODULE_MANAGER_HPP 3 | 4 | #include "safequeue.hpp" 5 | #include "message.hpp" 6 | #include "observer.hpp" 7 | 8 | class ModuleManager final : public Observer 9 | { 10 | private: 11 | static ModuleManager *sInstance; 12 | static std::mutex sMutex; 13 | SafeQueue> *mMsgQueue; 14 | 15 | protected: 16 | ModuleManager(); 17 | ModuleManager(const ModuleManager &) = delete; 18 | ModuleManager &operator=(const ModuleManager &) = delete; 19 | virtual ~ModuleManager(); 20 | 21 | public: 22 | static ModuleManager *getInstance(); 23 | virtual void update(std::shared_ptr msg) override; 24 | 25 | int start_record(void *params); 26 | void stop_record(int id); 27 | 28 | void handle_message(); 29 | }; 30 | 31 | #endif -------------------------------------------------------------------------------- /framework/safeMessageQueue/garbo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef GARBO_HPP 2 | #define GARBO_HPP 3 | 4 | /** 5 | * Description: This file is used to recycle singleton. 6 | * Author: Jinboom 7 | * Date: 2021/8 8 | */ 9 | 10 | /** 11 | * T is a pointer to a singleton. 12 | */ 13 | template 14 | class Garbo 15 | { 16 | private: 17 | /** 18 | * It must be T&. 19 | * Because garbo needs to be associated with the single instance to be 20 | * recycled, if a pointer is used, del is a null pointer when the single 21 | * instance is not created, and there is no chance to modify it later, 22 | * so del is always a null pointer, and this problem can be solved by using 23 | * a pointer reference. 24 | */ 25 | T &del; 26 | 27 | public: 28 | Garbo() = delete; 29 | explicit Garbo(T &d) : del(d){}; 30 | Garbo(const Garbo &) = delete; 31 | Garbo &operator=(const Garbo &) = delete; 32 | ~Garbo() 33 | { 34 | if (del) 35 | { 36 | delete del; 37 | del = nullptr; 38 | } 39 | } 40 | }; 41 | 42 | #endif -------------------------------------------------------------------------------- /framework/safeMessageQueue/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ModuleManager.hpp" 2 | #include 3 | 4 | int main() 5 | { 6 | // ModuleManager 是给上层模块调用的 7 | ModuleManager *mgr = ModuleManager::getInstance(); 8 | 9 | int id0 = mgr->start_record(nullptr); 10 | sleep(5); 11 | 12 | int id1 = mgr->start_record(nullptr); 13 | mgr->stop_record(id0); 14 | sleep(10); 15 | mgr->stop_record(id1); 16 | 17 | while (true) 18 | ; 19 | 20 | return 0; 21 | } -------------------------------------------------------------------------------- /framework/safeMessageQueue/message.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGE_HPP 2 | #define MESSAGE_HPP 3 | 4 | enum message_type_e 5 | { 6 | PVR_MSG_RECORD_START, 7 | PVR_MSG_RECORD_PAUSE, 8 | PVR_MSG_RECORD_RESTART, 9 | PVR_MSG_RECORD_STOP, 10 | HDD_MSG_SPACE_NOT_ENOUGH, 11 | }; 12 | 13 | struct dvr_action_t 14 | { 15 | int id; 16 | }; 17 | 18 | struct hdd_action_t 19 | { 20 | int id; 21 | }; 22 | 23 | union message_body_u 24 | { 25 | dvr_action_t dvr; 26 | hdd_action_t hdd; 27 | }; 28 | 29 | struct message_t 30 | { 31 | message_type_e what; 32 | message_body_u obj; 33 | }; 34 | 35 | #endif -------------------------------------------------------------------------------- /framework/safeMessageQueue/observe.cpp: -------------------------------------------------------------------------------- 1 | #include "observer.hpp" 2 | 3 | Observer::Observer() 4 | { 5 | mSubjects = new std::set(); 6 | } 7 | 8 | Observer::~Observer() 9 | { 10 | delete mSubjects; 11 | } 12 | 13 | void Observer::remove_subject(Subject &s) 14 | { 15 | mSubjects->erase(&s); 16 | } 17 | 18 | void Observer::set_subject(Subject &s) 19 | { 20 | mSubjects->insert(&s); 21 | s.register_observer(*this); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /framework/safeMessageQueue/observer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OBSERVER_HPP 2 | #define OBSERVER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include "message.hpp" 8 | #include "subject.hpp" 9 | 10 | class Subject; 11 | 12 | class Observer 13 | { 14 | protected: 15 | // for remove subject 16 | std::set *mSubjects; 17 | 18 | protected: 19 | Observer(); 20 | 21 | virtual ~Observer(); 22 | 23 | public: 24 | virtual void remove_subject(Subject &s); 25 | 26 | virtual void set_subject(Subject &s); 27 | 28 | virtual void update(std::shared_ptr msg) = 0; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /framework/safeMessageQueue/subject.cpp: -------------------------------------------------------------------------------- 1 | #include "subject.hpp" 2 | 3 | Subject::Subject() 4 | { 5 | mObservers = new std::set(); 6 | } 7 | 8 | Subject::~Subject() 9 | { 10 | /** 11 | * Subject has no right to deconstruct specific observer, 12 | * but must deconstruct its own set. 13 | */ 14 | for (const auto &o : *mObservers) 15 | { 16 | remove_observer(*o); 17 | } 18 | delete mObservers; 19 | } 20 | 21 | void Subject::register_observer(Observer &o) 22 | { 23 | mObservers->insert(&o); 24 | } 25 | 26 | void Subject::remove_observer(Observer &o) 27 | { 28 | o.remove_subject(*this); 29 | } 30 | 31 | void Subject::notify_observers(std::shared_ptr msg) 32 | { 33 | for (auto o : *mObservers) 34 | { 35 | o->update(msg); 36 | } 37 | return; 38 | } 39 | -------------------------------------------------------------------------------- /framework/safeMessageQueue/subject.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SUBJECT_HPP 2 | #define SUBJECT_HPP 3 | 4 | #include 5 | #include 6 | #include "message.hpp" 7 | #include "observer.hpp" 8 | 9 | class Observer; 10 | 11 | class Subject 12 | { 13 | protected: 14 | std::set *mObservers; 15 | 16 | protected: 17 | Subject(); 18 | 19 | virtual ~Subject(); 20 | 21 | public: 22 | virtual void register_observer(Observer &o); 23 | 24 | virtual void remove_observer(Observer &o); 25 | 26 | virtual void notify_observers(std::shared_ptr msg); 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /framework/safeRingBuffer/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ -g -Wall *.cpp -o main -pthread 3 | 4 | clean: 5 | rm main 6 | -------------------------------------------------------------------------------- /framework/safeRingBuffer/RingBuffer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RING_BUFFER_HPP 2 | #define RING_BUFFER_HPP 3 | 4 | /** 5 | * Description: This file is used to implement the ring buffer, 6 | * which is thread-safe. 7 | * Author: Jinboom 8 | * Date: 2021/8 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | using byte_t = unsigned char; 15 | 16 | class RingBuffer 17 | { 18 | public: 19 | RingBuffer(int id, int len); 20 | ~RingBuffer(); 21 | 22 | private: 23 | int mId; 24 | byte_t *mBuf; 25 | int mFront; 26 | int mRear; 27 | int mAllocSize; 28 | 29 | std::mutex mMutex; 30 | 31 | public: 32 | /** 33 | * std::vector style interface 34 | */ 35 | int size(); 36 | int capacity(); 37 | void resize(int len); 38 | bool empty(); 39 | void clear(); 40 | int push(byte_t *data, int len); 41 | int get(byte_t *data, int len); 42 | 43 | int free_size(); 44 | void show(); // for debug 45 | int get_id() const; 46 | }; 47 | 48 | #endif -------------------------------------------------------------------------------- /function/int2str.cpp: -------------------------------------------------------------------------------- 1 | void int2str(int n, char *str) 2 | { 3 | int num = n > 0 ? n : -n; 4 | if (str == nullptr) 5 | return; 6 | 7 | char buf[10] = " "; 8 | int i = 0, j = 0; 9 | while(num) 10 | { 11 | buf[i++] = num % 10 + '0'; 12 | num /= 10; 13 | } 14 | 15 | int len = n > 0 ? i : ++i; 16 | str[len] = '\0'; 17 | if (n < 0) 18 | { 19 | j = 1; 20 | str[0] = '-'; 21 | } 22 | 23 | for (; j < len; ++j) 24 | { 25 | str[j] = buf[len - 1 - j]; 26 | } 27 | } -------------------------------------------------------------------------------- /function/memcpy.cpp: -------------------------------------------------------------------------------- 1 | void* myMemcpy(void* memTo, void* memFrom, size_t size) 2 | { 3 | if (memTo == nullptr || memFrom == nullptr) 4 | return nullptr; 5 | char *tmpFrom = (char *)memFrom; 6 | char *tmpTo = (char *)memTo; 7 | while (size -- > 0) 8 | // while (size--) 9 | *tmpTo++ = *tmpFrom++; 10 | return memTo; 11 | } -------------------------------------------------------------------------------- /function/str2int.cpp: -------------------------------------------------------------------------------- 1 | int str2int(const char *str) 2 | { 3 | int tmp = 0; 4 | const char *ptr = str; 5 | if (*ptr == '-' || *ptr == '+') 6 | { 7 | ++ptr; 8 | } 9 | 10 | while (*ptr != '\0') 11 | { 12 | if (*ptr < '0' || *ptr > '9') 13 | { 14 | break; 15 | } 16 | tmp = tmp * 10 + *ptr - '0'; 17 | ++ptr; 18 | } 19 | ptr = str; // 重新让 ptr 指向字符数组的首地址 20 | if (*ptr == '-') 21 | tmp = -tmp; 22 | return tmp; 23 | } -------------------------------------------------------------------------------- /function/strcat.cpp: -------------------------------------------------------------------------------- 1 | char *myStrcat(char *dst, char *src) 2 | { 3 | assert(src != nullptr && dst != nullptr); // src 与 dst 非空 4 | assert(dst != src); // 不能让一个字符串与其本身连接 5 | 6 | char *dstCopy = dst; 7 | while (*dst) 8 | dst++; 9 | while (*dst++ = *src++); 10 | return dstCopy; 11 | } -------------------------------------------------------------------------------- /function/strcmp.cpp: -------------------------------------------------------------------------------- 1 | int myStrcmp(const char *src, const char *dst) 2 | { 3 | if (src != nullptr && dst == nullptr) 4 | return *src; 5 | else if (src == nullptr && dst == nullptr) 6 | return 0; 7 | else if (src == nullptr && dst != nullptr) 8 | return -*dst; 9 | 10 | while (*src && *dst && *src == *dst) 11 | { 12 | src++; 13 | dst++; 14 | } 15 | return *src - *dst; 16 | } -------------------------------------------------------------------------------- /function/strcpy.cpp: -------------------------------------------------------------------------------- 1 | char *strcpy(char *strDst, const char *strSrc) // 返回 char* 的目的是可以链式使用 2 | { 3 | if (strDst == nullptr || strSrc == nullptr) 4 | return nullptr; 5 | 6 | char *strDstCopy = strDst; 7 | while ((*strDst++ = *strSrc++) != '\0'); // 比较之后再自增,把 '\0' 也复制过去了 8 | return strDstCopy; 9 | } -------------------------------------------------------------------------------- /function/strlen.cpp: -------------------------------------------------------------------------------- 1 | int myStrlen(const char *str) 2 | { 3 | assert(str != nullptr); // 需要头文件 #include 4 | //if (str == nullptr) return 0; 5 | const char *p = str; 6 | while (*str++ != '\0'); 7 | return str - p - 1; 8 | } -------------------------------------------------------------------------------- /function/strstr.cpp: -------------------------------------------------------------------------------- 1 | // 返回索引的形式:例如 haystack:“abcde”,needle:”bcd“,返回 1 2 | int strStr(string haystack, string needle) { 3 | if (!needle.size()) 4 | return 0; 5 | if (!haystack.size()) 6 | return -1; 7 | 8 | int i = 0, j = 0; 9 | 10 | // haystack.size() - needle.size() + 1是无符号整型, 11 | // 有符号与无符号比较,自动把有符号转换成无符号 12 | while (i < int(haystack.size() - needle.size() + 1)) 13 | { 14 | while (j < needle.size()) 15 | { 16 | if (haystack[i] != needle[j]) 17 | { 18 | i = i - j + 1; 19 | j = 0; 20 | break; 21 | } 22 | else 23 | { 24 | ++i; 25 | ++j; 26 | } 27 | } 28 | if (j == needle.size()) 29 | return i - j; 30 | } 31 | return -1; 32 | } 33 | 34 | 35 | // 返回指针的形式:例如 src:"abcdef",sub:"cde", 36 | // 那么 strstr(src, sub) 会返回 src 中的字符 'c' 的地址,打印出来就是 "cdef" 37 | // 如果想得到偏移量(索引),让 strstr 的返回值减去 src 的首地址。 38 | const char *strstr(const char *src, const char* sub) 39 | { 40 | if (src == nullptr || sub == nullptr) 41 | return src; 42 | const char *psrc, *psrcCopy = src; 43 | const char *psub; 44 | 45 | while (*src) 46 | { 47 | psrc = src; 48 | psub = sub; 49 | do 50 | { 51 | if (!*psub) 52 | return src; 53 | } while (*psub++ == *psrc++); 54 | src += 1; 55 | } 56 | return psrcCopy; 57 | } -------------------------------------------------------------------------------- /function/swapInt.cpp: -------------------------------------------------------------------------------- 1 | // 基于加减法交换两个数 2 | void swap(int &x, int &y) 3 | { 4 | x = x + y; 5 | y = x - y; 6 | x = x - y; 7 | } 8 | 9 | // 基于异或运算交换两个数 10 | void swap1(int &x, int &y) 11 | { 12 | x ^= y; 13 | y ^= x; 14 | x ^= y; 15 | } 16 | -------------------------------------------------------------------------------- /function/swapStr.cpp: -------------------------------------------------------------------------------- 1 | // 引用符号 & 去掉就不能交换了,用引用指针代表传的指针是实参而不是形参,s1, s2便不是一个临时的拷贝。 2 | void swap(char *&s1, char *&s2) 3 | { 4 | char *tmp; 5 | tmp = s1; 6 | s1 = s2; 7 | s2 = tmp; 8 | } 9 | 10 | void swap2(char **s1, char **s2) 11 | { 12 | char **tmp; 13 | tmp = s1; 14 | s1 = s2; 15 | s2 = tmp; 16 | } 17 | 18 | int main(int argc, char* argv[]) { 19 | char * s1 = "hello "; 20 | char * s2 = "world "; 21 | cout << s1 << s2 << endl; 22 | swap(s1, s2); 23 | cout << s1 << s2 << endl; 24 | system("pause"); 25 | } 26 | /* 打印 27 | hello world 28 | world hello 29 | */ -------------------------------------------------------------------------------- /io/newcode.py: -------------------------------------------------------------------------------- 1 | n = int(input().strip()) 2 | for i in range(n): 3 | x, y = list(map(int, input().strip().split())) 4 | print(x+y) -------------------------------------------------------------------------------- /itcoder/acm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | # Python使用的是3.4.3,缩进可以使用tab、4个空格或2个空格,但是只能任选其中一种,不能多种混用 4 | while 1: 5 | a = [] 6 | s = input() 7 | 8 | if s != "": 9 | for x in s.split(): 10 | a.append(int(x)) 11 | 12 | print(sum(a)) 13 | else: 14 | break -------------------------------------------------------------------------------- /itcoder/hw1.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -* 2 | 3 | class Solution: 4 | def game2048(self, nums): 5 | size = 10 6 | cnt = 0 7 | while(True): 8 | #print("【1】", nums) 9 | if nums[size - 1] >= 2: 10 | return cnt + 1 11 | for i in range(size-2, -1, -1): # 【2】 12 | if nums[i] >= 2: # 【3】 13 | nums[i] -= 2 14 | cnt += 1 15 | if i < size-1: 16 | nums[i + 1] += 1 17 | else: 18 | return cnt 19 | #print("【3】", nums) 20 | break 21 | #print("【2】", nums) 22 | 23 | 24 | if __name__ == "__main__": 25 | f = Solution() 26 | elems = [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] 27 | t = int(input().strip()) 28 | for i in range(t): 29 | nums = list(map(int, input().strip().split())) 30 | # nums = [2, 1, 1, 1, 1, 1, 1, 1, 1, 1] 31 | target = 2048 32 | res = f.game2048(nums) 33 | print(res) 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /itcoder/hw2.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -* 2 | 3 | class Solution: 4 | def weight(self, nums): 5 | for x in nums: 6 | 7 | def trans(self, key, pai): 8 | if pai[1] == "J": # J 9 | pai = "J" 10 | elif pai[0] == "J": # 大小王 11 | pass 12 | else: 13 | pai = pai[1] # 其他牌 14 | return 1 + key.index(pai) 15 | 16 | if __name__ == "__main__": 17 | f = Solution() 18 | value = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14] 19 | key = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "J", "Q", "K", "A", "J1", "J2"] 20 | nums = [0] * 15 21 | t = int(input().strip()) 22 | elems = [] 23 | 24 | for i in range(t): 25 | elems.append(input().strip()) 26 | real_pai = [f.trans(key, x) for x in elems] 27 | for x in real_pai: 28 | nums[x] += 1 29 | print(nums) 30 | print(real_pai) 31 | 32 | 33 | """ 34 | 6 35 | C2 36 | D3 37 | S4 38 | C5 39 | C6 40 | C4 41 | """ 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /itcoder/qax.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def main(self): 3 | print("ok") 4 | 5 | 6 | if __name__ == "__main__": 7 | while(1): 8 | m = int(input().strip()) 9 | n = int(input().strip()) 10 | prices = list(map(int, input().strip().split())) 11 | M = int(input().strip()) 12 | 13 | 14 | print(m) 15 | print(n) 16 | print(prices) 17 | print(M) 18 | f = Solution() 19 | print(f.main()) -------------------------------------------------------------------------------- /sources/1x.svg: -------------------------------------------------------------------------------- 1 | 倍增倍增 -------------------------------------------------------------------------------- /sources/2.svg: -------------------------------------------------------------------------------- 1 | 二分二分 -------------------------------------------------------------------------------- /sources/2x.svg: -------------------------------------------------------------------------------- 1 | 分治分治 -------------------------------------------------------------------------------- /sources/all.svg: -------------------------------------------------------------------------------- 1 | 贪心贪心 -------------------------------------------------------------------------------- /sources/bfs.svg: -------------------------------------------------------------------------------- 1 | 广度优先搜索广度优先搜索 -------------------------------------------------------------------------------- /sources/c.svg: -------------------------------------------------------------------------------- 1 | C/C++C/C++ -------------------------------------------------------------------------------- /sources/coding.svg: -------------------------------------------------------------------------------- 1 | codingcodingdo itdo it -------------------------------------------------------------------------------- /sources/dfs.svg: -------------------------------------------------------------------------------- 1 | 深度优先搜索深度优先搜索 -------------------------------------------------------------------------------- /sources/dp.svg: -------------------------------------------------------------------------------- 1 | 动态规划动态规划 -------------------------------------------------------------------------------- /sources/fsm.svg: -------------------------------------------------------------------------------- 1 | 有限状态机有限状态机 -------------------------------------------------------------------------------- /sources/g.svg: -------------------------------------------------------------------------------- 1 | 图论图论 -------------------------------------------------------------------------------- /sources/graph.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sources/hash.svg: -------------------------------------------------------------------------------- 1 | 哈希哈希 -------------------------------------------------------------------------------- /sources/heap.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sources/list.svg: -------------------------------------------------------------------------------- 1 | 线性表线性表 -------------------------------------------------------------------------------- /sources/py.svg: -------------------------------------------------------------------------------- 1 | PythonPython -------------------------------------------------------------------------------- /sources/q.svg: -------------------------------------------------------------------------------- 1 | 队列队列 -------------------------------------------------------------------------------- /sources/readme.md: -------------------------------------------------------------------------------- 1 |  2 | ### 算法 3 | 4 | 1. 排序算法:快速排序、归并排序、计数排序 5 | 2. 搜索算法:回溯、递归、剪枝技巧 6 | 3. 图论:最短路、最小生成树、网络流建模 7 | 4. 动态规划:背包问题、最长子序列、计数问题 8 | 5. 基础技巧:分治、倍增、二分、贪心 9 | 10 | ### 数据结构 11 | 12 | 1. 数组与链表:单 / 双向链表、跳舞链 13 | 2. 栈和队列 14 | 3. 树:最近公共祖先、并查集 15 | 4. 哈希表 16 | 5. 堆:大 / 小根堆、可并堆 17 | 6. 字符串:字典树、后缀树 18 | 19 | 20 | 21 | 22 | 23 | ### 常见标签编码 24 | C/CC![](c.svg)`![](sources/c.svg)` 25 | Python![](py.svg)`![](sources/py.svg)` 26 | #### 算法 27 | - 排序![](sort.svg)`![](sources/sort.svg)` 28 | - 搜索![](search.svg)`![](sources/search.svg)` 29 | - 图论![](g.svg)`![](sources/g.svg)` 30 | - 动态规划![](dp.svg)`![](sources/dp.svg)` 31 | - 基础技巧 32 | - 分治![](2x.svg)`![](sources/2x.svg)` 33 | - 倍增![](1x.svg)`![](sources/1x.svg)` 34 | - 二分![](2.svg)`![](sources/2.svg)` 35 | - 贪心![](all.svg)`![](sources/all.svg)` 36 | 37 | #### 数据结构 38 | - 线性表![](list.svg)`![](sources/list.svg)` 39 | - 栈![](stack.svg)`![](sources/stack.svg)` 40 | - 队列![](q.svg)`![](sources/q.svg)` 41 | - 树![](graph.svg)`![](sources/graph.svg)` 42 | - 哈希![](hash.svg)`![](sources/hash.svg)` 43 | - 堆![](heap.svg)`![](sources/heap.svg)` 44 | - 字符串![](str.svg)`![](sources/str.svg)` -------------------------------------------------------------------------------- /sources/search.svg: -------------------------------------------------------------------------------- 1 | 搜索搜索 -------------------------------------------------------------------------------- /sources/sort.svg: -------------------------------------------------------------------------------- 1 | 排序排序 -------------------------------------------------------------------------------- /sources/stack.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sources/str.svg: -------------------------------------------------------------------------------- 1 | 字符串字符串 -------------------------------------------------------------------------------- /sources/tree.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sources/union.svg: -------------------------------------------------------------------------------- 1 | 并查集并查集 -------------------------------------------------------------------------------- /usefulLink/coding.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/usefulLink/coding.md -------------------------------------------------------------------------------- /剑指offer/10-fibonacci数列/fibonacci.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 大家都知道斐波那契数列,现在要求输入一个整数n, 4 | 请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39 5 | """ 6 | 7 | 8 | class Solution: 9 | def Fibonacci1(self, n): 10 | # write code here 11 | 12 | if n == 0: 13 | return 0 14 | if n == 1 or n == 2: 15 | return 1 16 | if n > 2: 17 | return self.Fibonacci1(n-1) + self.Fibonacci1(n-2) 18 | 19 | def Fibonacci2(self, n): 20 | # write code here 21 | 22 | f0 = 0 23 | f1 = 1 24 | f2 = 0 25 | if n == 0: 26 | return f0 27 | elif n == 1: 28 | return f1 29 | else: 30 | for i in range(2, n + 1): 31 | f2 = f1 + f0 32 | f1, f0 = f2, f1 33 | return f2 34 | 35 | 36 | s = Solution() 37 | l = [] 38 | for i in range(9): 39 | l.append(s.Fibonacci2(i)) 40 | print(l) -------------------------------------------------------------------------------- /剑指offer/10-fibonacci数列/jumpFloor.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int jumpFloor(int number) { 4 | if (number <= 0) 5 | return 0; 6 | else if (number == 1 || number == 2) 7 | return number; 8 | int fn_1 = 2, fn_2 = 1; // f(n-1) 与 f(n-2) 9 | int fn; 10 | for (int i = 3; i <= number; ++i) 11 | { 12 | fn = fn_1 + fn_2; // f(n) = f(n-1) + f(n-2) 13 | fn_2 = fn_1; 14 | fn_1 = fn; 15 | } 16 | return fn; 17 | } 18 | }; -------------------------------------------------------------------------------- /剑指offer/10-fibonacci数列/jumpFloor.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 一只青蛙一次可以跳上1级台阶,也可以跳上2级。 4 | 求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。 5 | """ 6 | 7 | 8 | class Solution: 9 | def jumpFloor(self, n): 10 | """ 11 | 提示: 12 | 设 n 级台阶有 f(n) 种跳法,青蛙最后一次跳,有两种跳法: 13 | 若最后一次跳只跳一个台阶则前面的 n-1 级有 f(n-1) 种方法 14 | 若最后一次跳只跳两个台阶则前面的 n-2 级有 f(n-2) 种方法 15 | """ 16 | # write code here 17 | 18 | f0 = 0 19 | f1 = 1 20 | f2 = 0 21 | if n == 0: 22 | return f0 23 | elif n == 1: 24 | return f1 25 | else: 26 | for i in range(2, n + 1): 27 | f2 = f1 + f0 28 | f1, f0 = f2, f1 29 | return f2 30 | 31 | -------------------------------------------------------------------------------- /剑指offer/10-fibonacci数列/jumpFloor2.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | public: 4 | int jumpFloorII(int number) { 5 | if (number <= 0) 6 | return 0; 7 | else if (number == 1) 8 | return number; 9 | int fn = 1; 10 | for (int i = 2; i <= number; ++i) 11 | fn *= 2; 12 | return fn; 13 | } 14 | }; -------------------------------------------------------------------------------- /剑指offer/10-fibonacci数列/jumpFloor2.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目: 4 | 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。 5 | 求该青蛙跳上一个n级的台阶总共有多少种跳法。 6 | """ 7 | 8 | class Solution: 9 | def jumpFloorII(self, number): 10 | """ 11 | 提示: 12 | 设 n 级台阶有 f(n) 中跳法,青蛙最后一次跳,有 n 种跳法: 13 | 若最后一次跳只跳 1 个台阶则前面的 n-1 级有 f(n-1) 种方法 14 | 若最后一次跳只跳 2 个台阶则前面的 n-2 级有 f(n-2) 种方法 15 | ... 16 | 若最后一次跳只跳 n-1 个台阶则前面的 1 级有 f(1) 种方法 17 | 若最后一次跳只跳 n 个台阶只有 1 种方法,(一步直接跳上来) 18 | 所以 f(n) = f(n-1) + f(n-2) + ... + f(1) + 1 (1) 19 | 把 n - 1 代入上式 n 中得: 20 | f(n-1) = f(n-2) + f(n-3) + ... + f(1) + 1 (2) 21 | (1) - (2) 可得 f(n) = 2f(n-1),这是个等比数列。 22 | 但写程序直接按照(1)式来写就好了。 23 | """ 24 | # write code here 25 | 26 | f = [0, 1, 2] 27 | if number in f: # 当 number 处于闭区间 [0, 2]时,恰有f[number] = number 28 | return number 29 | 30 | for i in range(3, number + 1): 31 | f.append(sum(f) + 1) 32 | # f[i] = f[0] + f[1] + ... + f[i-1] + 1 = sum(f) + 1 33 | # 加 1 是因为青蛙可以一次跳 i 级台阶。 34 | return f[-1] 35 | 36 | -------------------------------------------------------------------------------- /剑指offer/10-fibonacci数列/rectCover.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。 4 | 请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 5 | """ 6 | 7 | 8 | class Solution: 9 | def rectCover(self, number): 10 | """ 11 | 最后一次覆盖是竖着覆盖则前面的 2*(n-1) 矩形有 f(n-1) 种方法, 12 | 最后一次覆盖是横着覆盖则前面的 2*(n-2) 矩形有 f(n-2) 种方法 13 | """ 14 | # write code here 15 | 16 | f0 = 0 17 | f1 = 1 18 | f2 = 2 19 | if number == 0: 20 | return f0 21 | elif number == 1: 22 | return f1 23 | elif number == 2: 24 | return f2 25 | else: 26 | for i in range(3, number + 1): 27 | f3 = f2 + f1 28 | f2, f1 = f3, f2 29 | return f3 -------------------------------------------------------------------------------- /剑指offer/11-旋转数组的最小数字/JZ11.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int minNumberInRotateArray(vector rotateArray) { 4 | if (rotateArray.empty()) 5 | return 0; 6 | // 特例:把最开始的零个元素搬到数组的末尾,即数组未旋转。 7 | if (rotateArray[0] < rotateArray[rotateArray.size() - 1]) 8 | return rotateArray[0]; 9 | 10 | int begin = 0, end = rotateArray.size() - 1; 11 | int mid = 0; 12 | 13 | while (begin < end) 14 | { 15 | if (end - begin == 1) 16 | return rotateArray[end]; 17 | mid = (begin + end)/2; 18 | if (rotateArray[begin] == rotateArray[mid] && rotateArray[mid] == rotateArray[end]) 19 | { 20 | int m = rotateArray[begin]; 21 | for (int i = begin + 1; i <= end; ++i) 22 | if (rotateArray[i] < m) 23 | m = rotateArray[i]; 24 | return m; 25 | } 26 | else if (rotateArray[begin] <= rotateArray[mid]) 27 | begin = mid; 28 | else 29 | end = mid; 30 | } 31 | } 32 | }; -------------------------------------------------------------------------------- /剑指offer/13-机器人的运动范围/JZ13.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 题目: 3 | 地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动, 4 | 每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 5 | 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。 6 | 但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子? 7 | */ 8 | 9 | 10 | class Solution { 11 | public: 12 | int movingCount(int threshold, int rows, int cols) 13 | { 14 | vector > vis(rows, vector(cols, 0)); 15 | return moving(threshold, rows, cols, 0, 0, vis); 16 | } 17 | 18 | int moving(int threshold, int rows, int cols, int i, int j, vector >& vis) 19 | { 20 | // 机器人已经移动到了坐标 (i, j),满足下面三个 if 条件的该格子就不能达到。 21 | // 把能达到的格子坐标记录到 vis 列表中,用来判断下个满足条件的格子是否已经走过了。 22 | if (sumNumber(i) + sumNumber(j) > threshold) 23 | return 0; 24 | else if (i < 0 || i >= rows || j < 0 || j >= cols) 25 | return 0; 26 | else if (vis[i][j]) 27 | return 0; 28 | vis[i][j] = 1; 29 | return 1 + moving(threshold, rows, cols, i - 1, j, vis) 30 | + moving(threshold, rows, cols, i + 1, j, vis) 31 | + moving(threshold, rows, cols, i, j - 1, vis) 32 | + moving(threshold, rows, cols, i, j + 1, vis); 33 | } 34 | 35 | int sumNumber(int x) 36 | { 37 | if (x <= 0) 38 | return 0; 39 | int res = 0; 40 | while (x) 41 | { 42 | res += x % 10; 43 | x /= 10; 44 | } 45 | return res; 46 | } 47 | }; -------------------------------------------------------------------------------- /剑指offer/13-机器人的运动范围/movingCount.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目: 4 | 地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动, 5 | 每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 6 | 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。 7 | 但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子? 8 | """ 9 | 10 | 11 | class Solution: 12 | 13 | def __init__(self): 14 | self.vis = [] 15 | 16 | def movingCount(self, threshold, rows, cols): 17 | # write code here 18 | return self.moving(threshold, rows, cols, 0, 0) 19 | 20 | def moving(self, threshold, rows, cols, i, j): 21 | """ 22 | 机器人已经移动到了坐标 (i, j),满足下面三个 if 条件的该格子就不能达到。 23 | 把能达到的格子坐标记录到 vis 字典中, 24 | """ 25 | if self.sumNumber(i) + self.sumNumber(j) > threshold: 26 | return 0 27 | if i >= rows or j >= cols or i < 0 or j < 0: 28 | return 0 29 | if (i, j) in self.vis: 30 | return 0 31 | self.vis.append((i, j)) 32 | 33 | return 1 + self.moving(threshold, rows, cols, i - 1, j) \ 34 | + self.moving(threshold, rows, cols, i + 1, j) \ 35 | + self.moving(threshold, rows, cols, i, j - 1) \ 36 | + self.moving(threshold, rows, cols, i, j + 1) 37 | 38 | def sumNumber(self, x): 39 | if x <= 0: 40 | return 0 41 | res = 0 42 | while x: 43 | res += x % 10 44 | x /= 10 45 | return res 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /剑指offer/14-剪绳子/JZ14.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 把长度为 n 的绳子剪成 m 段,m, n 均为整数(可以剪零刀),问 m 小段绳子长度之积最大为多少? 3 | 比如: 4 | 长度为 8 的绳子可以剪成 3,3,2 三段,其积最大为 18。 5 | 长度为 3 的绳子不剪,其积最大为 3。 6 | 7 | 【注意】 8 | 牛客网上的题意是绳子必须得剪一次,所以长度为 3 的绳子其积最大为 2(剪成长度为 1 和 2 的两段) 9 | 10 | C++ 代码是绳子至少剪一次的实现,同文件夹下 Python 代码是绳子可以不剪的实现 11 | */ 12 | 13 | class Solution 14 | { 15 | public: 16 | int cutRope(int number) 17 | { 18 | int *dp = new int[number + 1]; 19 | dp[0] = 0, dp[1] = dp[2] = 1, dp[3] = 2; // 绳子必须得剪一次 20 | if (number < 4) 21 | return dp[number]; 22 | for (int i = 0; i < 4; ++i) // 当 number >= 4 的时候,dp[0~3的部分] 不剪比剪要好 23 | dp[i] = i; 24 | int max = 0; 25 | for (int i = 4; i <= number; ++i) 26 | { 27 | // 对于一段长度为 i 的绳子,第一刀剪 j 长度,则 f(i) = max(f(j) * f(i-j)), 28 | // 和第一刀剪 i-j 长度,第二刀剪 j 长度本质上是一样的 29 | for (int j = 1; j <= i / 2; ++j) 30 | { 31 | dp[i] = dp[j] * dp[i - j]; 32 | max = dp[i] > max ? dp[i] : max; 33 | dp[i] = max; 34 | } 35 | } 36 | return dp[number]; 37 | } 38 | }; 39 | 40 | #include 41 | 42 | int main() 43 | { 44 | Solution s; 45 | std::cout << s.cutRope(1) << " " 46 | << s.cutRope(5) << " " 47 | << s.cutRope(6) << " " 48 | << s.cutRope(7) << " " 49 | << s.cutRope(8) << " " << std::endl; 50 | } -------------------------------------------------------------------------------- /剑指offer/15-二进制中1的个数/JZ15.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 输入一个整数,输出该数二进制表示中 1 的个数。其中负数用补码表示。 3 | 有必要了解,对负数,右移左边补 1 4 | 对正数右移,左边补零 5 | */ 6 | 7 | /* 一种方法是将数字 n 右移,与 1 与,但这样可能会引起死循环, 8 | 因为当 n 为负数的时候,n 的最高位补码为 1, 9 | 这样一直右移,最终这个数字就会变成 0xFFFFFFFF,而陷入死循环。 10 | 为了避免死循环,设置 flag = 1,将 flag 左移, 11 | 在 32 位机器上 flag 移动 32 次就会变成 0,跳出 while 循环。 12 | */ 13 | 14 | int numberOf1(int n) 15 | { 16 | unsigned int count = 0; 17 | unsigned int flag = 1; 18 | while (flag) 19 | { 20 | if (n & flag) 21 | count++; 22 | flag = flag << 1; 23 | } 24 | return count; 25 | } -------------------------------------------------------------------------------- /剑指offer/15-二进制中1的个数/numberOf1.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 输入一个整数,输出该数二进制表示中 1 的个数。其中负数用补码表示。 4 | 有必要了解,对负数,右移左边补 1 5 | 对正数右移,左边补零 6 | """ 7 | 8 | 9 | class Solution: 10 | def NumberOf1(self, n): 11 | """ 12 | 将 n 与 1 作与运算,统计结果是否为 1,然后再右移 n, 13 | 但这样有一个 bug,对于负数,符号位是 1,右移会导致结果变成 0xFFFFFFFF,陷入死循环, 14 | 或者像 python 实现一样,限制移位操作次数, 15 | 或者考虑不右移 n,而是左移 1 再与 n与。 16 | """ 17 | # write code here 18 | 19 | return sum([(n >> i & 1) for i in range(32)]) 20 | """ 21 | 对负数会引起死循环 22 | count = 0 23 | while n: 24 | count += (n & 1) 25 | n = n>>1 26 | return count 27 | """ 28 | 29 | if __name__ == "__main__": 30 | f = Solution() 31 | print(f.NumberOf1(-11)) -------------------------------------------------------------------------------- /剑指offer/16-数值的整数次方/JZ16.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Solution { 4 | public: 5 | // 比如求 3的 31 次方 result,如果知道 3 的 15 次方为 a,那么可知 3 的 30次方为 = a * a , 6 | // 由于 31 为奇数所以再在 3 的 30 次方基础上再乘以 3,时间复杂度 O(logn)。 7 | double Power(double base, int exponent) { 8 | if (exponent == 0) 9 | return 1; 10 | if (exponent == 1) 11 | return base; 12 | double result = Power(base, exponent >> 1); 13 | result *= result; 14 | if (exponent & 1) // 奇数与 1 位与为 true 15 | result *= base; 16 | return result; 17 | } 18 | }; -------------------------------------------------------------------------------- /剑指offer/16-数值的整数次方/Power.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 4 | """ 5 | 6 | 7 | class Solution: 8 | def Power1(self, base, exponent): 9 | # write code here 10 | 11 | result = 1 12 | for i in range(abs(exponent)): # 当 exponent = 0 时,range(0) 为空,不会执行循环,直接返回 result = 1 13 | result *= base 14 | if exponent < 0: 15 | return 1/result 16 | else: 17 | return result 18 | 19 | def Power2(self, base, exponent): # 优化方法 20 | if not exponent: # 这里定义 0 的 0 次方为 1 21 | return 1 22 | if not base: 23 | return 0 24 | result = self.Power2(base, abs(exponent) >> 1) 25 | result *= result 26 | if abs(exponent) & 1: # 奇数的二进制最后一个数字必为 1, 与 1 位与结果为 1 27 | result *= base 28 | if exponent < 0: 29 | result = 1/result 30 | return result 31 | 32 | if __name__ == "__main__": 33 | f = Solution() 34 | print(f.Power2(2.5, 7)) 35 | 36 | -------------------------------------------------------------------------------- /剑指offer/18-删除链表的节点/deleteNode.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目: 4 | 在列表中删除一个节点,要求时间复杂度 O(1) 5 | """ 6 | 7 | import sys 8 | 9 | 10 | def deleteNode(): 11 | """ 12 | 提示: 13 | 由于不知道该节点的前驱,那就只能把后缀赋给该节点,然后将该节点的 next 指向下个节点的下一个节点。 14 | 如 a->b->c->i->j->k->z->None,要删除 i,由于不知道 i 的前驱,那就把 j 的值赋给 i,然后让 i.next 指向 k,就相当于删除 i 了。 15 | 特殊情况: 16 | 1,若该节点就是尾节点,那就只能通过 head 指针顺序找到该尾节点的前驱,然后让该前驱的指针域指向 None 17 | 2,若链表中只有一个节点,要删除该节点,把链表的头节点设置为 None 18 | """ 19 | pass 20 | 21 | if __name__ == "__main__": 22 | pass 23 | -------------------------------------------------------------------------------- /剑指offer/18-删除链表的节点/deleteduplication.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点, 4 | 重复的结点不保留,返回链表头指针。 5 | 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 6 | """ 7 | 8 | 9 | class ListNode: 10 | def __init__(self, x): 11 | self.val = x 12 | self.next = None 13 | 14 | 15 | class Solution: 16 | def deleteDuplication(self, pHead): 17 | """ 18 | 提示: 19 | 对该题中一个排序的链表,如果它的头节点 Head 与下一个节点 pNext 不同, 20 | 那么 Head 一定是不会重复的,但 pNext 就不一定了。 21 | 因此再递归处理以 pNext 为头节点的子链表,使该子链表返回的头节点一定不重复。 22 | """ 23 | # write code here 24 | 25 | if pHead is None or pHead.next is None: 26 | # 若为空链表或者只含有一个节点,那自然不会有重复的,直接返回就好 27 | return pHead 28 | 29 | pNext = pHead.next 30 | 31 | if pHead.val != pNext.val: 32 | # pHead.val 与 pNext.val 不相等,至少可以判断 pHead 不会是重复的节点,但 pNext 就不一定了。 33 | # 所以这里保留 PHead,并使 PHead 的指针域指向 self.deleteDuplication(pNext) 的头节点。 34 | pHead.next = self.deleteDuplication(pNext) 35 | return pHead 36 | else: 37 | while pHead.val == pNext.val and pNext.next is not None: 38 | pNext = pNext.next 39 | if pHead.val != pNext.val: 40 | # 从 pHead.next 到 pNext 的前面一个节点都应该被删除, 41 | # 所以直接让 pHead 而不是 pHead.next 指向 self.deleteDuplication(pNext) 的头节点 42 | pHead = self.deleteDuplication(pNext) 43 | return pHead 44 | else: # pNext 指向 None,到了尾部 45 | return None 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /剑指offer/18-删除链表的节点/mainJZ18-2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 题目: 3 | 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点, 4 | 重复的结点不保留,返回链表头指针。 5 | 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 6 | */ 7 | 8 | class Solution 9 | { 10 | public: 11 | ListNode *deleteDuplication(ListNode *pHead) 12 | { 13 | /* 14 | 提示: 15 | 对该题中一个排序的链表,如果它的头节点 Head 与下一个节点 pNext 不同, 16 | 那么 Head 一定是不会重复的,但 pNext 就不一定了。 17 | 因此再递归处理以 pNext 为头节点的子链表,使该子链表返回的头节点一定不重复。 18 | 递归就是,后面的都已经处理好了。 19 | */ 20 | if (pHead == nullptr || pHead->next == nullptr) // 链表为空或者只有一个节点 21 | return pHead; 22 | ListNode *pNext = pHead->next; 23 | if (pHead->val != pNext->val) 24 | { 25 | pHead->next = deleteDuplication(pNext); 26 | return pHead; 27 | } 28 | while (pHead->val == pNext->val && pNext->next != nullptr) 29 | { 30 | pNext = pNext->next; 31 | } 32 | // 若是不满足 pHead->val == pNext->val 而退出 while 循环,说明 pHead 到 pNext 之前的值都重复,应该删去 33 | if (pHead->val != pNext->val) 34 | { 35 | pHead = deleteDuplication(pNext); 36 | return pHead; 37 | } 38 | // 若是不满足 pNext != nullptr 而退出 while 循环,说明从 pHead 到尾节点的节点值都重复,全部删去 39 | else 40 | { 41 | pHead = nullptr; 42 | return pHead; 43 | } 44 | } 45 | }; -------------------------------------------------------------------------------- /剑指offer/18-删除链表的节点/mainJZ18.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 题目: 3 | 在列表中删除一个节点,要求时间复杂度 O(1) 4 | 5 | 提示: 6 | 由于不知道该节点的前驱,那就只能把后缀赋给该节点,然后将该节点的 next 指向下个节点的下一个节点。 7 | 如 a->b->c->i->j->k->z->None,要删除 i,由于不知道 i 的前驱,那就把 j 的值赋给 i,然后让 i.next 指向 k,就相当于删除 i 了。 8 | 特殊情况: 9 | 1,若该节点就是尾节点,那就只能通过 head 指针顺序找到该尾节点的前驱,然后让该前驱的指针域指向 None 10 | 2,若链表中只有一个节点,要删除该节点,把链表的头节点设置为 None 11 | */ 12 | void deleteNode(ListNode *pListHead, ListNode *pToBeDeleted) 13 | { 14 | if (pListHead == nullptr || pToBeDeleted == nullptr) 15 | return; 16 | if (pToBeDeleted->next != nullptr) // 要删除的节点不是尾节点 17 | { 18 | ListNode *pNext = pToBeDeleted->next; 19 | pToBeDeleted->val = pNext->val; 20 | pToBeDeleted->next = pNext->next; 21 | 22 | delete pNext; 23 | pNext = nullptr; 24 | } 25 | else if (pListHead == pToBeDeleted) // 链表只有一个节点,删除头节点 26 | { 27 | delete pToBeDeleted; 28 | pToBeDeleted = nullptr; 29 | pListHead = nullptr; 30 | } 31 | else // 链表中有多个节点,且要删除的节点是尾节点 32 | { 33 | ListNode *pNode = pListHead; 34 | while (pNode->next != pToBeDeleted) 35 | { 36 | pNode = pNode->next; 37 | } 38 | pNode->next = nullptr; 39 | delete pToBeDeleted; 40 | pToBeDeleted = nullptr; 41 | } 42 | } -------------------------------------------------------------------------------- /剑指offer/19-正则表达式匹配/JZ19.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool match(char* str, char* pattern) 4 | { 5 | if (str == nullptr || pattern == nullptr) 6 | return false; 7 | else if (*str != '\0' && *pattern == '\0') 8 | return false; 9 | else if (*str == '\0' && *pattern == '\0') 10 | return true; 11 | // 当 pattern 不是指向 "\0" 的时候 12 | if (*(pattern + 1) == '*') // pattern 第二个字符为 '*',情况考虑复杂 13 | { 14 | if (*str == *pattern || (*pattern == '.' && *str != '\0')) 15 | return match(str + 1, pattern + 2) // aab 和 a*a*b 16 | || match(str + 1, pattern) // aab 和 a*b 17 | || match(str, pattern + 2); // aab 和 a*a*a*a*a*b 18 | else // *str 与 *pattern 不匹配,如 bac 和 a*bac 19 | return match(str, pattern + 2); 20 | } 21 | else if (*str == *pattern || (*pattern == '.' && *str != '\0')) 22 | return match(str + 1, pattern + 1); 23 | else 24 | return false; 25 | } 26 | }; -------------------------------------------------------------------------------- /剑指offer/19-正则表达式匹配/match.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 请实现一个函数用来匹配包括'.'和'*'的正则表达式。 4 | 模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 5 | 在本题中,匹配是指字符串的所有字符匹配整个模式。 6 | 例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配 7 | """ 8 | 9 | 10 | class Solution: 11 | # s, pattern 都是字符串 12 | def match(self, s, pattern): 13 | # write code here 14 | 15 | # 字符串和模板长度均为零时匹配 16 | if len(s) == 0 and len(pattern) == 0: 17 | return True 18 | # 模板为空而字符串不为空肯定不匹配,但反过来字符串为空模板不为空可能匹配。 19 | if len(s) > 0 and len(pattern) == 0: 20 | return False 21 | if len(pattern) > 1 and pattern[1] == '*': # 这里考虑了模板包含 '.*' 的情况 22 | if len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.'): 23 | # 若s[0]已经与模板匹配,则包含有三种情况继续往下比较是否匹配 24 | # 一、形如 "aab" 与 "a*b" 用 self.match(s[1:], pattern) 继续判断后面的是否匹配 25 | # 二、形如 "aab" 与 "a*a*b" 用 self.match(s[1:], pattern[2:]) 继续判断后面的是否匹配 26 | # 三、形如 "aab" 与 "a*a*a*d*d*d*d*a*b" 必须用 self.match(s, pattern[2:]) 跳过一些没有用的模板 27 | return self.match(s[1:], pattern) or self.match(s[1:], pattern[2:]) or self.match(s, pattern[2:]) 28 | else: 29 | # 不满足条件说明模板中对应的那个字符在字符串中出现零个,所以取后移两位的新模板 30 | # 形如 "aab" 与 "c*a*b*" 31 | return self.match(s, pattern[2:]) 32 | else: 33 | if len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.'): 34 | return self.match(s[1:], pattern[1:]) 35 | else: 36 | return False -------------------------------------------------------------------------------- /剑指offer/20-表示数值的字符串/isNumeric.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。 4 | 例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 5 | 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。 6 | """ 7 | 8 | import re 9 | 10 | 11 | class Solution: 12 | """ 13 | """ 14 | def isNumeric(self, s): 15 | """ 16 | 正则表达式 17 | 18 | """ 19 | # write code here 20 | 21 | # return re.match(r"^[+-]?[0-9]*(\.[0-9]*)?([eE][+-]?[0-9]+)?$",s) 22 | # if re.match(r"^[+-]?[0-9]+[0-9]*([\.]+[1-9]+[0-9]*)?([eE][+-]?[0-9]+)?$", s): 23 | if re.match(r"^[+-]?[0-9]*(\.[0-9]*)?([eE][+-]?[0-9]+)?$", s): 24 | return True 25 | else: 26 | return False 27 | 28 | def isNumeric2(self, s): 29 | """ 30 | 作弊法 31 | 32 | """ 33 | # write code here 34 | try: 35 | float(s) 36 | except: 37 | return False 38 | return True 39 | 40 | 41 | if __name__ == "__main__": 42 | f = Solution() 43 | ss = ['e2', '.e2', '009.e', '+.e-9'] 44 | f1 = [] 45 | f2 = [] 46 | for s in ss: 47 | 48 | f1.append(f.isNumeric(s)) 49 | f2.append(f.isNumeric2(s)) 50 | print("两者在我的测试实例中,不一样,但在牛客网上均通过。很奇妙") 51 | print(f1) 52 | print(f2) 53 | 54 | -------------------------------------------------------------------------------- /剑指offer/21-调整数组顺序使奇数位于偶数前面/JZ21.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分。 3 | 【假设保证奇数和奇数,偶数和偶数之间的相对位置不变,又如何做?】 4 | */ 5 | 6 | class Solution { 7 | public: 8 | void reOrderArray(vector &array) { 9 | // 方法一:类似冒泡排序,前面一个数为偶后面一个数为奇就调换位置,保证相对位置不变,时间复杂度为 O(nlogn) 10 | if (array.empty()) 11 | return; 12 | int n = array.size(); 13 | for (int i = 0; i < n - 1; ++i) 14 | for (int j = 0; j < n - 1 - i; ++j) 15 | if (!isOdd(array[j]) && isOdd(array[j + 1])) 16 | { 17 | int t = array[j]; 18 | array[j] = array[j + 1]; 19 | array[j + 1] = t; 20 | } 21 | } 22 | 23 | void reOrderArray2(vector &arr) { 24 | // 方法二:类似快排过程的 partition,但不保证相对位置不变,时间复杂度为 O(n) 25 | if (arr.empty()) 26 | return; 27 | vector::iterator p1 = arr.begin(), p2 = arr.end() - 1; 28 | while (p1 < p2) 29 | { 30 | while (isOdd(*p1) && p1 < p2) 31 | p1++; 32 | while (!isOdd(*p2) && p1 < p2) 33 | p2--; 34 | if (p1 < p2) 35 | { 36 | int tmp = *p1; 37 | *p1 = *p2; 38 | *p2 = tmp; 39 | } 40 | } 41 | } 42 | 43 | bool isOdd(int n) 44 | { 45 | return n & 1; 46 | } 47 | 48 | // 如果想保证奇数和奇数,偶数和偶数之间的相对位置不变,可以使用稳定性排序比如冒泡排序,只是需要改变比较大小的条件。 49 | }; -------------------------------------------------------------------------------- /剑指offer/22-链表中倒数第k个节点/JZ22.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 题目: 3 | 输入一个链表,输出该链表中倒数第 k 个结点。 4 | 5 | 提示: 6 | 倒数第 k 个结点就意味着该结点再走 k-1 次就可以到达尾结点, 7 | 那么当一个快指针先从头结点处移动 k-1 次,然后快指针与慢指针同时移动, 8 | 当快指针到底尾节点,慢指针就刚好到达了倒数第 k 个结点 9 | */ 10 | 11 | class Solution 12 | { 13 | public: 14 | ListNode *FindKthToTail(ListNode *pListHead, unsigned int k) 15 | { 16 | if (pListHead == nullptr || k == 0) // 倒数第 0 个节点不存在 17 | return nullptr; 18 | ListNode *pSlow = pListHead; 19 | ListNode *pFast = pListHead; 20 | unsigned int cnt = 1; 21 | while (cnt < k) 22 | { 23 | if (pFast->next) 24 | pFast = pFast->next; 25 | else // 当 k 超过链表长度的时候 26 | return nullptr; 27 | cnt++; 28 | } 29 | while (pFast->next) 30 | { 31 | pFast = pFast->next; 32 | pSlow = pSlow->next; 33 | } 34 | return pSlow; 35 | } 36 | }; -------------------------------------------------------------------------------- /剑指offer/24-反转链表/JZ24.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 输入一个链表,反转链表后,输出新链表的表头。 3 | */ 4 | 5 | class Solution 6 | { 7 | public: 8 | /** 9 | * 用多个指针分别记录当前节点,以及它的前驱和后继。 10 | */ 11 | ListNode *ReverseList(ListNode *pHead) 12 | { 13 | if (pHead == nullptr || pHead->next == nullptr) // 链表为空或者只含有一个结点 14 | return pHead; 15 | 16 | ListNode *pre = nullptr; 17 | ListNode *pNode = pHead; 18 | ListNode *pNext = pNode->next; 19 | 20 | while (pNext) 21 | { 22 | pNode->next = pre; 23 | pre = pNode; 24 | pNode = pNext; 25 | pNext = pNode->next; 26 | } 27 | // 此时 pNext 为空,pNode 为头结点 28 | pNode->next = pre; 29 | return pNode; 30 | } 31 | }; -------------------------------------------------------------------------------- /剑指offer/24-反转链表/reverseList.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 输入一个链表,反转链表后,输出新链表的表头。 4 | """ 5 | 6 | # class ListNode: 7 | # def __init__(self, x): 8 | # self.val = x 9 | # self.next = None 10 | 11 | 12 | class Solution: 13 | # 返回ListNode 14 | def ReverseList(self, pHead): 15 | """ 16 | 用多个指针分别记录当前节点,以及它的前驱和后继。 17 | """ 18 | # write code here 19 | 20 | if pHead is None: 21 | return None 22 | else: 23 | if pHead.next: 24 | pre = None 25 | pNode = pHead 26 | pNext = pNode.next 27 | pNode.next = pre 28 | else: # 链表只含有一个节点 29 | return pHead 30 | 31 | while pNext: 32 | if pNext.next: 33 | pNextNext = pNext.next 34 | pre = pNode 35 | pNode = pNext 36 | pNext = pNextNext 37 | pNode.next = pre 38 | else: # pNext即是尾节点 39 | pNext.next = pNode 40 | return pNext 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /剑指offer/25-合并两个排序的链表/JZ25.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 题目: 3 | * 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。 4 | */ 5 | 6 | /* 7 | struct ListNode { 8 | int val; 9 | struct ListNode *next; 10 | ListNode(int x) : 11 | val(x), next(NULL) { 12 | } 13 | };*/ 14 | class Solution 15 | { 16 | public: 17 | /** 18 | * 提示: 19 | 非常类似归并排序的归并过程: 20 | 若两链表任何一个为空,则返回剩下的那一个; 21 | 若均不为空,则找到两个链表中值小的那个,添加到新链表尾部; 22 | 若最后有某一个链表为空,说明它的节点都被添加到新链表上,直接把另一个非空链表剩下部分添到到新链表尾部 23 | */ 24 | ListNode *Merge(ListNode *pHead1, ListNode *pHead2) 25 | { 26 | if (pHead1 == nullptr) 27 | return pHead2; 28 | else if (pHead2 == nullptr) 29 | return pHead1; 30 | 31 | ListNode *head = nullptr; 32 | if (pHead1->val < pHead2->val) 33 | { 34 | head = pHead1; 35 | pHead1 = pHead1->next; 36 | } 37 | else 38 | { 39 | head = pHead2; 40 | pHead2 = pHead2->next; 41 | } 42 | 43 | ListNode *p = head; 44 | while (pHead1 && pHead2) 45 | { 46 | if (pHead1->val < pHead2->val) 47 | { 48 | p->next = pHead1; 49 | pHead1 = pHead1->next; 50 | p = p->next; 51 | } 52 | else 53 | { 54 | p->next = pHead2; 55 | pHead2 = pHead2->next; 56 | p = p->next; 57 | } 58 | } 59 | 60 | if (pHead1) 61 | p->next = pHead1; 62 | else if (pHead2) 63 | p->next = pHead2; 64 | return head; 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /剑指offer/25-合并两个排序的链表/merge.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目: 4 | 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。 5 | """ 6 | 7 | # class ListNode: 8 | # def __init__(self, x): 9 | # self.val = x 10 | # self.next = None 11 | 12 | 13 | class Solution: 14 | # 返回合并后列表 15 | def Merge(self, pHead1, pHead2): 16 | """ 17 | 提示: 18 | 非常类似归并排序的归并过程: 19 | 若两链表任何一个为空,则返回剩下的那一个; 20 | 若均不为空,则找到两个链表中值小的那个,添加到新链表尾部; 21 | 若最后有某一个链表为空,说明它的节点都被添加到新链表上,直接把另一个非空链表剩下部分添到到新链表尾部 22 | """ 23 | # write code here 24 | 25 | if pHead1 is None: 26 | return pHead2 27 | if pHead2 is None: 28 | return pHead1 29 | 30 | p1 = pHead1 31 | p2 = pHead2 32 | if pHead1.val < pHead2.val: 33 | head = p1 34 | p1 = p1.next 35 | else: 36 | head = p2 37 | p2 = p2.next 38 | 39 | p = head 40 | 41 | while p1 and p2: 42 | if p1.val < p2.val: 43 | p.next = p1 44 | p = p.next 45 | p1 = p1.next 46 | else: 47 | p.next = p2 48 | p = p.next 49 | p2 = p2.next 50 | 51 | if p1: 52 | p.next = p1 53 | if p2: 54 | p.next = p2 55 | return head 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /剑指offer/26-树的子结构/JZ26.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) 3 | */ 4 | 5 | /* 6 | struct TreeNode { 7 | int val; 8 | struct TreeNode *left; 9 | struct TreeNode *right; 10 | TreeNode(int x) : val(x), left(NULL), right(NULL) { } 11 | };*/ 12 | class Solution { 13 | public: 14 | bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) 15 | { 16 | bool result = false; 17 | if (pRoot1 != nullptr && pRoot2 != nullptr) // 空树不是任何一个树的子结构 18 | { 19 | if (pRoot1->val == pRoot2->val) // 根节点相等的时候,才逐个比较两树的结点 20 | result = isSubTree(pRoot1, pRoot2); 21 | if (!result) // 根结点虽相同,但其他结点不同时,寻找 pRoot1 的左右子节点中是否有子树 pRoot2 22 | result = HasSubtree(pRoot1->left, pRoot2) || 23 | HasSubtree(pRoot1->right, pRoot2); 24 | } 25 | return result; 26 | } 27 | 28 | bool isSubTree(TreeNode* pRoot1, TreeNode* pRoot2) 29 | { 30 | if (pRoot2 == nullptr) // 只要 pRoot2 为空,就说明遍历完了子树,返回 true 31 | return true; 32 | if (pRoot1 == nullptr) // 必须先判断 pRoot2,在判断 pRoot1 是否为空 33 | return false; 34 | if (pRoot2->val != pRoot1->val) 35 | return false; 36 | else 37 | return isSubTree(pRoot1->left, pRoot2->left) && 38 | isSubTree(pRoot1->right, pRoot2->right); 39 | } 40 | }; -------------------------------------------------------------------------------- /剑指offer/26-树的子结构/hasSubTree.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) 4 | """ 5 | 6 | 7 | # -*- coding:utf-8 -*- 8 | # class TreeNode: 9 | # def __init__(self, x): 10 | # self.val = x 11 | # self.left = None 12 | # self.right = None 13 | 14 | class Solution: 15 | 16 | def HasSubtree(self, pRoot1, pRoot2): 17 | # write code here 18 | if pRoot1 is None or pRoot2 is None: 19 | return False 20 | return self.search(pRoot1, pRoot2) 21 | 22 | def search(self, A, B): 23 | """ 24 | search(A,B) 用于指定在树 A 的哪个节点上会找到一个子树跟 B 一样,用 isSubTree() 函数判断 A 中的某一个子树是否与 B 一样 25 | """ 26 | if A.left and A.right: 27 | return self.search(A.left, B) or self.search(A.right, B) or self.isSubTree(A, B) \ 28 | or self.isSubTree(A.left, B) or self.isSubTree(A.right, B) 29 | if A.left: 30 | return self.search(A.left, B) or self.isSubTree(A, B) or self.isSubTree(A.left, B) \ 31 | or self.isSubTree(A.right, B) 32 | if A.right: 33 | return self.search(A.right, B) or self.isSubTree(A, B) or self.isSubTree(A.left, B) \ 34 | or self.isSubTree(A.right, B) 35 | 36 | def isSubTree(self, A, B): 37 | """ 38 | 把树 A 与 B 逐元素比对,判断 A 是否包含 B 39 | """ 40 | if B is None: 41 | return True 42 | elif A is None or A.val != B.val: 43 | return False 44 | else: # A 与 B 的 val 值相等 45 | return self.isSubTree(A.left, B.left) and self.isSubTree(A.right, B.right) 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /剑指offer/27-二叉树的镜像/JZ27.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | 操作给定的二叉树,将其变换为源二叉树的镜像。 3 | 二叉树的镜像定义:源二叉树 4 | 8 5 | / \ 6 | 6 10 7 | / \ / \ 8 | 5 7 9 11 9 | 镜像二叉树 10 | 8 11 | / \ 12 | 10 6 13 | / \ / \ 14 | 11 9 7 5 15 | */ 16 | 17 | /** 18 | 提示: 19 | 无论是左右子节点是否为空,交换指针就行了,再以子节点为根节点,递归调用 20 | */ 21 | class Solution { 22 | public: 23 | void Mirror(TreeNode *pRoot) { 24 | if (pRoot == nullptr) 25 | return; 26 | TreeNode *pTmp = pRoot->left; 27 | pRoot->left = pRoot->right; 28 | pRoot->right = pTmp; 29 | Mirror(pRoot->left); 30 | Mirror(pRoot->right); 31 | } 32 | }; -------------------------------------------------------------------------------- /剑指offer/27-二叉树的镜像/mirror.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 操作给定的二叉树,将其变换为源二叉树的镜像。 4 | 二叉树的镜像定义:源二叉树 5 | 8 6 | / \ 7 | 6 10 8 | / \ / \ 9 | 5 7 9 11 10 | 镜像二叉树 11 | 8 12 | / \ 13 | 10 6 14 | / \ / \ 15 | 11 9 7 5 16 | """ 17 | 18 | 19 | # class TreeNode: 20 | # def __init__(self, x): 21 | # self.val = x 22 | # self.left = None 23 | # self.right = None 24 | 25 | 26 | class Solution: 27 | # 返回镜像树的根节点 28 | def Mirror(self, root): 29 | """ 30 | 提示: 31 | 无论是左右子节点是否为空,交换指针就行了,再以子节点为根节点,递归调用 32 | """ 33 | # write code here 34 | 35 | if root is None: 36 | return 37 | root.left, root.right = root.right, root.left 38 | self.Mirror(root.left) 39 | self.Mirror(root.right) 40 | -------------------------------------------------------------------------------- /剑指offer/3-数组中重复的数字/JZ3.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 题目: 3 | 在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。 4 | 数组中某些数字是重复的,但不知道有几个数字是重复的, 5 | 也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 6 | 例如,如果输入长度为7的数组 {2,3,1,0,2,5,3}, 7 | 那么对应的输出是重复的数字 2 或者 3。 8 | */ 9 | 10 | class Solution { 11 | public: 12 | // Parameters: 13 | // numbers: an array of integers 14 | // length: the length of array numbers 15 | // duplication: (Output) the duplicated number in the array number 16 | // Return value: true if the input is valid, and there are some duplications in the array number 17 | // otherwise false 18 | bool duplicate(int numbers[], int length, int* duplication) { 19 | if (numbers == nullptr || length == 0) 20 | return false; 21 | // 检查数据是否在区间[0, length-1]内 22 | for (int i = 0; i < length; ++i) 23 | { 24 | if (numbers[i] < 0 || numbers[i] >= length) 25 | return false; 26 | } 27 | 28 | for (int i = 0; i < length; ++i) 29 | { 30 | while (numbers[i] != i) 31 | { 32 | if (numbers[i] == numbers[numbers[i]]) 33 | { 34 | *duplication = numbers[i]; 35 | return true; // 有重复的数字 36 | } 37 | swap(numbers[i], numbers[numbers[i]]); 38 | } 39 | } 40 | return false; // 没有重复数字 41 | } 42 | 43 | void swap(int& x, int& y) 44 | { 45 | int t = y; 46 | y = x; 47 | x = t; 48 | } 49 | }; -------------------------------------------------------------------------------- /剑指offer/30-包含min函数的栈/JZ30.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 题目: 3 | * 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数 (时间复杂度应为 O(1))。 4 | */ 5 | 6 | class Solution 7 | { 8 | stack stk; 9 | stack minstk; 10 | 11 | public: 12 | void push(int value) 13 | { 14 | if (minstk.empty() || value <= minstk.top()) // 注意是 <= 15 | minstk.push(value); 16 | stk.push(value); 17 | } 18 | void pop() 19 | { 20 | if (minstk.top() == stk.top()) 21 | { 22 | minstk.pop(); 23 | stk.pop(); 24 | } 25 | else 26 | stk.pop(); 27 | } 28 | int top() 29 | { 30 | return stk.top(); 31 | } 32 | int min() 33 | { 34 | return minstk.top(); 35 | } 36 | }; -------------------------------------------------------------------------------- /剑指offer/30-包含min函数的栈/min.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目: 4 | 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数 (时间复杂度应为 O(1))。 5 | """ 6 | 7 | 8 | class Solution: 9 | def __init__(self): 10 | self.stack = [] 11 | self.minStack = [] 12 | 13 | def push(self, node): 14 | # write code here 15 | if self.minStack == []: 16 | self.minStack.append(node) 17 | elif node <= self.minStack[-1]: 18 | self.minStack.append(node) 19 | self.stack.append(node) 20 | 21 | def pop(self): 22 | # write code here 23 | if self.stack[-1] == self.minStack[-1]: 24 | self.minStack.pop() 25 | return self.stack.pop() 26 | 27 | def top(self): 28 | # write code here 29 | return self.stack[-1] 30 | 31 | def min(self): 32 | # write code here 33 | return self.minStack[-1] -------------------------------------------------------------------------------- /剑指offer/31-栈的压入弹出序列/JZ31.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 题目: 3 | 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。 4 | 假设压入栈的所有数字均不相等。 5 | 例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列, 6 | 但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) 7 | */ 8 | 9 | class Solution 10 | { 11 | public: 12 | /** 13 | * 按照 popV 里的顺序出栈,如果能把 pushV 出栈成空栈,说明 popV 是一种可能的弹出顺序。 14 | */ 15 | bool IsPopOrder(vector pushV, vector popV) 16 | { 17 | if (pushV.size() != popV.size()) 18 | return false; 19 | int length = pushV.size(); 20 | int idPush = 0, idPop = 0; 21 | stack stk; 22 | while (idPush < length && idPop < length) 23 | { 24 | stk.push(pushV[idPush]); 25 | while (!stk.empty() && stk.top() == popV[idPop]) 26 | { 27 | stk.pop(); 28 | idPop++; 29 | } 30 | ++idPush; 31 | } 32 | // 退出循环有两种情况: 33 | // 一、idPush 等于 idPop 等于 length,此时 stk 为空,说明 popV 是弹出序列 34 | // 二、idPush 等于 length,已经压入了最后一个元素,但 stk.top() 还是不等于 popV[idPop] 35 | if (stk.empty()) 36 | return true; 37 | else 38 | return false; 39 | } 40 | }; -------------------------------------------------------------------------------- /剑指offer/31-栈的压入弹出序列/isPopOrder.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目: 4 | 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。 5 | 假设压入栈的所有数字均不相等。 6 | 例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列, 7 | 但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) 8 | """ 9 | 10 | 11 | class Solution: 12 | def IsPopOrder(self, pushV, popV): 13 | """ 14 | 按照 popV 里的顺序出栈,如果能把 pushV 出栈成空栈,说明 popV 是一种可能的弹出顺序。 15 | """ 16 | # write code here 17 | p = 0 18 | 19 | while pushV and popV: 20 | print(p, pushV, popV) 21 | if pushV[p] == popV[0]: 22 | del pushV[p] 23 | del popV[0] 24 | p -= 1 25 | elif pushV[p] != popV[0] and p + 1 == len(pushV): 26 | return False 27 | else: 28 | p += 1 29 | return True 30 | 31 | 32 | if __name__ == "__main__": 33 | pushV = [1, 2, 3, 4, 5] 34 | popV = [4, 5, 3, 2, 1] 35 | f = Solution() 36 | print(f.IsPopOrder(pushV, popV)) 37 | -------------------------------------------------------------------------------- /剑指offer/32-从上到下打印二叉树/JZ32-2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。 3 | 1 4 | / \ 5 | 2 3 6 | / \ \ 7 | 4 5 7 8 | 9 | 输出:[[1], [2, 3], [4, 5, 7]] 10 | */ 11 | 12 | /** 13 | 把每一层节点都存到容器中 14 | */ 15 | 16 | class Solution 17 | { 18 | public: 19 | vector> Print(TreeNode *pRoot) 20 | { 21 | vector> vec2d; // 每一层都存到一个 vector 容器中 22 | if (pRoot == nullptr) 23 | return vec2d; 24 | 25 | vector vec; // 存 Node 里的值 26 | // C++11 中 vector 可以像数组一样用花括号初始化,且等于号可以省。 27 | vector vecNode{pRoot}; 28 | while (!vecNode.empty()) 29 | { 30 | vector thisLayer(vecNode); // 存 Node 31 | for (int i = 0; i < thisLayer.size(); ++i) 32 | { 33 | vec.push_back(thisLayer[i]->val); 34 | } 35 | vec2d.push_back(vec); 36 | vec.clear(); 37 | vecNode.clear(); 38 | for (int i = 0; i < thisLayer.size(); ++i) 39 | { 40 | if (thisLayer[i]->left != nullptr) 41 | vecNode.push_back(thisLayer[i]->left); 42 | if (thisLayer[i]->right != nullptr) 43 | vecNode.push_back(thisLayer[i]->right); 44 | } 45 | thisLayer.clear(); 46 | } 47 | return vec2d; 48 | } 49 | }; -------------------------------------------------------------------------------- /剑指offer/32-从上到下打印二叉树/JZ32.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | 题目: 3 | 从上往下打印出二叉树的每个节点,同层节点从左至右打印。 4 | 1 5 | / \ 6 | 2 3 7 | / \ \ 8 | 4 5 7 9 | 10 | 输出:[1, 2, 3, 4, 5, 7] 11 | */ 12 | 13 | /** 14 | 提示:使用队列存储节点。 15 | 根节点先入队,找到队头元素的左右孩子(如果有的话)入队,再使队头元素出队, 16 | 此时会有新的队头元素,再找新队头的左右孩子入队,再使新队头出队。 17 | 如此反复,直至出队操作使队列再次为空 18 | */ 19 | class Solution 20 | { 21 | public: 22 | vector PrintFromTopToBottom(TreeNode *root) 23 | { 24 | vector vec; 25 | if (root == nullptr) 26 | return vec; 27 | 28 | queue queueNode; 29 | queueNode.push(root); 30 | 31 | while (!queueNode.empty()) 32 | { 33 | TreeNode *pNode = queueNode.front(); 34 | queueNode.pop(); 35 | vec.push_back(pNode->val); 36 | if (pNode->left) 37 | queueNode.push(pNode->left); 38 | if (pNode->right) 39 | queueNode.push(pNode->right); 40 | } 41 | return vec; 42 | } 43 | }; -------------------------------------------------------------------------------- /剑指offer/32-从上到下打印二叉树/printFormTopToBottom.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目: 4 | 从上往下打印出二叉树的每个节点,同层节点从左至右打印。 5 | 1 6 | / \ 7 | 2 3 8 | / \ \ 9 | 4 5 7 10 | 11 | 输出:[1, 2, 3, 4, 5, 7] 12 | """ 13 | 14 | # class TreeNode: 15 | # def __init__(self, x): 16 | # self.val = x 17 | # self.left = None 18 | # self.right = None 19 | 20 | 21 | class Solution: 22 | # 返回从上到下每个节点值列表,例:[1,2,3] 23 | def PrintFromTopToBottom(self, root): 24 | """ 25 | 提示:使用队列存储节点。 26 | 根节点先入队,找到队头元素的左右孩子(如果有的话)入队,再使队头元素出队, 27 | 此时会有新的队头元素,再找新队头的左右孩子入队,再使新队头出队。 28 | 如此反复,直至出队操作使队列再次为空 29 | """ 30 | # write code here 31 | if root is None: 32 | return [] 33 | queue = [root] 34 | LValue = [] 35 | while queue: 36 | this = queue.pop() 37 | LValue.append(this.val) 38 | if this.left: 39 | queue.insert(0, this.left) 40 | if this.right: 41 | queue.insert(0, this.right) 42 | return LValue 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /剑指offer/32-从上到下打印二叉树/printManyLines.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。 4 | 1 5 | / \ 6 | 2 3 7 | / \ \ 8 | 4 5 7 9 | 10 | 输出:[[1], [2, 3], [4, 5, 7]] 11 | """ 12 | 13 | 14 | # class TreeNode: 15 | # def __init__(self, x): 16 | # self.val = x 17 | # self.left = None 18 | # self.right = None 19 | 20 | 21 | class Solution: 22 | 23 | def Print(self, pRoot): 24 | """ 25 | 提示: 26 | 把每一层节点都存到队列(列表)中 27 | """ 28 | # write code here 29 | 30 | if pRoot is None: 31 | return [] 32 | queue = [pRoot] 33 | LValue = [] 34 | while queue: 35 | thisLayer = queue[:] 36 | del queue[:] 37 | tValue = [] 38 | for node in thisLayer: 39 | tValue.append(node.val) 40 | LValue.append(tValue) 41 | for node in thisLayer: 42 | if node.left: 43 | queue.append(node.left) 44 | if node.right: 45 | queue.append(node.right) 46 | return LValue -------------------------------------------------------------------------------- /剑指offer/32-从上到下打印二叉树/printZHI.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 请实现一个函数按照之字形打印二叉树, 4 | 即第一行按照从左到右的顺序打印, 5 | 第二层按照从右至左的顺序打印, 6 | 第三行按照从左到右的顺序打印,其他行以此类推。 7 | 8 | 1 9 | / \ 10 | 2 3 11 | / \ \ 12 | 4 5 7 13 | 14 | 输出:[[1], [3, 2], [4, 5, 7]] 15 | """ 16 | 17 | # class TreeNode: 18 | # def __init__(self, x): 19 | # self.val = x 20 | # self.left = None 21 | # self.right = None 22 | 23 | 24 | class Solution: 25 | def Print(self, pRoot): 26 | # write code here 27 | 28 | if pRoot is None: 29 | return [] 30 | queue = [pRoot] 31 | deep = 1 32 | LValue = [] 33 | while queue: 34 | thisLayer = queue[:] 35 | del queue[:] 36 | tValue = [] 37 | if self.way(deep) == 'rightToLeft': 38 | [tValue.append(node.val) for node in thisLayer[::-1]] 39 | else: 40 | [tValue.append(node.val) for node in thisLayer] 41 | LValue.append(tValue) 42 | for node in thisLayer: 43 | if node.left: 44 | queue.append(node.left) 45 | if node.right: 46 | queue.append(node.right) 47 | if queue: 48 | deep += 1 49 | return LValue 50 | 51 | def way(self, deep): 52 | if deep & 1: # 奇数 53 | return 'leftToRight' 54 | else: 55 | return 'rightToLeft' 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /剑指offer/34-二叉树中和为某一值的路径/JZ34.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。 3 | 路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。 4 | 5 | 10 6 | / \ 7 | 5 12 8 | / \ 9 | 4 7 10 | 11 | 如找和为 22 的路径,则输出: 12 | [[10, 5, 7], [10, 12]] 13 | 如找和(即期望值)为 15 的路径,则输出 [[]], 14 | 虽然从 10->5 是一个路径,但不是题目中描述的从根节点到叶子节点的路径 15 | */ 16 | 17 | /** 18 | * 提示: 19 | * 递归。判断左右子树中是否存在路径和为期望值减去当前节点值的路径。 20 | */ 21 | 22 | class Solution 23 | { 24 | public: 25 | vector> vec2d; 26 | vector vec; 27 | vector> FindPath(TreeNode *root, int expectNumber) 28 | { 29 | if (root == nullptr) //【1】 30 | return vec2d; 31 | vec.push_back(root->val); 32 | // 【2】处:路径指的是从根结点到叶子结点 33 | if (root->val == expectNumber && root->left == nullptr && root->right == nullptr) //【2】 34 | vec2d.push_back(vec); 35 | if (root->left) //【3】 36 | FindPath(root->left, expectNumber - root->val); 37 | if (root->right) //【4】 38 | FindPath(root->right, expectNumber - root->val); 39 | // 【5】处:假设从根节点到某叶子结点的路径满足条件,那么肯定在【2】处被添加到 vec2d 里的, 40 | // 显然,【3】【4】处的 if 内是进不去的,此时只要 vec 不为空,就弹出最后面的元素。 41 | if (!vec.empty()) //【5】 42 | vec.pop_back(); 43 | return vec2d; 44 | } 45 | }; -------------------------------------------------------------------------------- /剑指offer/34-二叉树中和为某一值的路径/findPath.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。 4 | 路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。 5 | 6 | 10 7 | / \ 8 | 5 12 9 | / \ 10 | 4 7 11 | 12 | 如找和为 22 的路径,则输出: 13 | [[10, 5, 7], [10, 12]] 14 | 如找和为 15 的路径,则输出 [[]], 15 | 虽然从 10->5 是一个路径,但不是题目中描述的从根节点到叶子节点的路径 16 | """ 17 | 18 | 19 | # class TreeNode: 20 | # def __init__(self, x): 21 | # self.val = x 22 | # self.left = None 23 | # self.right = None 24 | class Solution: 25 | # 返回二维列表,内部每个列表表示找到的路径 26 | def FindPath(self, root, expectNumber): 27 | # write code here 28 | 29 | if not root: 30 | return [] 31 | if root and root.val == expectNumber and not root.left and not root.right: 32 | return [[root.val]] 33 | path = [] 34 | left = self.FindPath(root.left, expectNumber - root.val) 35 | right = self.FindPath(root.right, expectNumber - root.val) 36 | for subPath in left + right: 37 | path.append([root.val] + subPath) 38 | return path 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /剑指offer/38-字符串的排列/pailie.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目:(这个题目与剑指 offer 不同) 4 | 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串 aabc, 5 | 则打印出字符串中不同字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 6 | """ 7 | 8 | 9 | class Solution: 10 | def Permutation(self, ss): 11 | # write code here 12 | s = sorted(list(set([*ss]))) 13 | print(s) 14 | return self.pailie(s, len(s)) 15 | 16 | def pailie(self, s, n): 17 | if n < 2: 18 | return s 19 | yy = self.pailie(s, n - 1) 20 | t = [self.merge(x, y) for x in s for y in yy] 21 | t = [x for x in t if x] 22 | print(n, t) 23 | return t 24 | 25 | def merge(self, x, y): 26 | if x not in y: 27 | return x + y 28 | else: 29 | return None 30 | 31 | 32 | if __name__ == "__main__": 33 | 34 | f = Solution() 35 | s = 'acba' 36 | f.Permutation(s) -------------------------------------------------------------------------------- /剑指offer/4-二维数组中的查找/JZ4.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 在一个二维数组中(每个一维数组的长度相同), 3 | 每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 4 | 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 5 | */ 6 | 7 | class Solution { 8 | public: 9 | bool Find(int target, vector > array) { 10 | /* 11 | 提示: 12 | 将 target 与数组右上角所在的元素比较: 13 | 相等:返回找到了 14 | 小于:该元素所在的那一列里肯定是找不到的,只会存在于该元素左边所在的矩形区域 15 | 大于:该元素所在的那一行里肯定是找不到的,只会存在于该元素下方所在的矩形区域 16 | */ 17 | if (array.empty()) 18 | return false; 19 | const int rows = array.size(); 20 | const int cols = array[0].size(); 21 | int r = 0, c = cols - 1; 22 | 23 | while (r >= 0 && r < rows && c >= 0 && c < cols) 24 | { 25 | if (array[r][c] == target) 26 | return true; 27 | else if (target > array[r][c]) 28 | r++; 29 | else 30 | c--; 31 | } 32 | return false; 33 | } 34 | }; -------------------------------------------------------------------------------- /剑指offer/4-二维数组中的查找/find.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 在一个二维数组中(每个一维数组的长度相同), 4 | 每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 5 | 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 6 | """ 7 | 8 | 9 | class Solution: 10 | # array 二维列表 11 | def find(self, target, array): 12 | """ 13 | 提示: 14 | 将 target 与数组右上角所在的元素比较: 15 | 相等:返回找到了 16 | 小于:该元素所在的那一列里肯定是找不到的,只会存在于该元素左边所在的矩形区域 17 | 大于:该元素所在的那一行里肯定是找不到的,只会存在于该元素下方所在的矩形区域 18 | """ 19 | # write code here 20 | 21 | if not array: 22 | return False 23 | row = 0 24 | col = len(array[0]) - 1 25 | while col >= 0 and row <= len(array) - 1: 26 | if array[row][col] == target: 27 | return True 28 | if array[row][col] > target: 29 | col -= 1 30 | else: 31 | row += 1 32 | return False 33 | -------------------------------------------------------------------------------- /剑指offer/45-把数组排成最小的数/PrintMinNumber.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 输入一个正整数数组,把数组里所有数字拼接起来排成一个数, 4 | 打印能拼接出的所有数字中最小的一个。 5 | 例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。 6 | """ 7 | 8 | 9 | class Solution: 10 | def PrintMinNumber(self, numbers): 11 | # write code here 12 | numbers = [str(x) for x in numbers] 13 | result = '' 14 | while numbers: 15 | m = self.newMin(numbers) 16 | result += m 17 | numbers.remove(m) 18 | return result 19 | 20 | def newMin(self, ss): 21 | if len(ss) > 1: 22 | m = ss[0] 23 | for s in ss[1:]: 24 | if self.compare(s, m) < 0: 25 | m = s 26 | return m 27 | elif len(ss) == 1: 28 | return ss[0] 29 | else: 30 | return '' 31 | 32 | def compare(self, s1, s2): 33 | """ 34 | python 中字符比较大小: 35 | '3' > '2' # True 36 | '3' > '' # True 37 | 38 | 定义新的比较规则: 39 | s1 > s2 的比较结果与 s1s2 拼接的字符 > s2s1 拼接的字符的比较结果一致。 40 | """ 41 | if s1 + s2 > s2 + s1: 42 | return 1 43 | elif s1 + s2 < s2 + s1: 44 | return -1 45 | else: 46 | return 0 47 | 48 | if __name__ == "__main__": 49 | a = [3, 32, 321] 50 | s1 = '321' 51 | s2 = '32' 52 | f = Solution() 53 | num = f.PrintMinNumber(a) 54 | print(num) -------------------------------------------------------------------------------- /剑指offer/49-丑数/ugly.py: -------------------------------------------------------------------------------- 1 | """ 2 | 把只包含质因子2、3和5的数称作丑数(Ugly Number)。 3 | 例如6、8都是丑数,但14不是,因为它包含质因子7。 4 | 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。 5 | """ 6 | 7 | 8 | class Solution: 9 | def GetUglyNumber_Solution(self, index): 10 | """ 11 | 丑数只包含质因子2、3和5,那么将之前已经计算的丑数与2、3、5相乘,得到的数必定是丑数,取得到的最小的数。 12 | """ 13 | if index < 1: 14 | return 0 15 | res = [0] * index 16 | res[0] = 1 17 | id2 = id3 = id5 = 0 18 | for i in range(1, index): 19 | res[i] = min(res[id2] * 2, res[id3] * 3, res[id5] * 5) 20 | if res[i] == res[id2] * 2: 21 | id2 += 1 22 | if res[i] == res[id3] * 3: 23 | id3 += 1 24 | if res[i] == res[id5] * 5: 25 | id5 += 1 26 | return res[-1] 27 | 28 | 29 | if __name__ == "__main__": 30 | f = Solution() 31 | f.GetUglyNumber_Solution(int(input())) -------------------------------------------------------------------------------- /剑指offer/5-替换空格/replaceBlank.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 实现一个函数,将一个字符串中的每个空格替换成“%20”。 4 | 例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 5 | """ 6 | 7 | 8 | class Solution: 9 | # s 源字符串 10 | def replaceSpace(self, s): 11 | # write code here 12 | t = '' 13 | for i in s: 14 | if i == ' ': 15 | i = '%20' 16 | t += i 17 | return t 18 | -------------------------------------------------------------------------------- /剑指offer/52-两个链表的第一个公共结点/JZ52.py: -------------------------------------------------------------------------------- 1 | """ 2 | 题目: 3 | 输入两个链表,找出它们的第一个公共结点。 4 | """ 5 | 6 | # -*- coding:utf-8 -*- 7 | # class ListNode: 8 | # def __init__(self, x): 9 | # self.val = x 10 | # self.next = None 11 | 12 | 13 | class Solution: 14 | def FindFirstCommonNode(self, pHead1, pHead2): 15 | """ 16 | 提示: 17 | 假设链表 1 是 1->2->3->6->7,链表 2 是 4->5->6->7。 18 | 法一: 19 | 若有公共结点,那么从尾结点开始向前比较,那么最后一个相同的结点就是要找的公共结点, 20 | 但由于是单链表不知道前驱,所以考虑用两个栈分别存储两链表结点,不断判断栈顶元素是否相同,找到最后一个相同的元素。 21 | 代码略。 22 | 23 | 法二: 24 | 两链表有长有短,设长链表比短链表长 cnt,两个指针 pLong、pShort 分别指向长、短链表头, 25 | 让 pLong 先在长链表上走动 cnt,再两指针同时走,遇到的第一个相同结点就是公共结点了。 26 | """ 27 | # write code here 28 | if (not (pHead1 and pHead2)): # 有一个为空就返回空 29 | return None 30 | length1 = self.getListLength(pHead1) 31 | length2 = self.getListLength(pHead2) 32 | if length1 >= length2: 33 | pLong = pHead1 34 | pShort = pHead2 35 | else: 36 | pLong = pHead2 37 | pShort = pHead1 38 | cnt = abs(length1 - length2) 39 | while cnt: 40 | pLong = pLong.next 41 | cnt -= 1 42 | while pLong and pShort and pLong != pShort: 43 | pLong = pLong.next 44 | pShort = pShort.next 45 | return pLong 46 | 47 | def getListLength(self, head): 48 | length = 0 49 | p = head 50 | while p: 51 | length += 1 52 | p = p.next 53 | return length -------------------------------------------------------------------------------- /剑指offer/55-二叉树的深度/JZ55.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目: 4 | 输入一棵二叉树,求该树的深度。 5 | 从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 6 | """ 7 | 8 | # class TreeNode: 9 | # def __init__(self, x): 10 | # self.val = x 11 | # self.left = None 12 | # self.right = None 13 | 14 | 15 | class Solution: 16 | def TreeDepth(self, pRoot): 17 | """ 18 | 提示: 19 | 若该数有左右子树,则其深度为其子树深度 + 1(1为根)中大的那一个 20 | 21 | """ 22 | # write code here 23 | if pRoot is None: 24 | return 0 25 | nLeft = self.TreeDepth(pRoot.left) + 1 26 | nRight = self.TreeDepth(pRoot.right) + 1 27 | return nLeft if nLeft >= nRight else nRight -------------------------------------------------------------------------------- /剑指offer/58-反转单词顺序/JZ58-2.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目:左旋转字符串 4 | 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。 5 | 对于一个给定的字符序列 S,请你把其循环左移 K 位后的序列输出。 6 | 例如,字符序列 S=”abcXYZdef”,要求输出循环左移 3 位后的结果,即 “XYZdefabc”。 7 | """ 8 | 9 | 10 | class Solution: 11 | def LeftRotateString(self, s, n): 12 | """ 13 | 提示: 14 | 对于 C++ 可以先实现一个函数,以反转字符串的某一段。 15 | 将字符串分成两部分 s[:n] 和 s[n:],分别翻转这两部分,然后再对整个字符串翻转。 16 | S = "abcXYZdef",n = 3 17 | S[:3] = "abc", S[3:] = "XYZdef" 18 | 翻转后: 19 | S[:3] = "cba", S[3:] = "fedZYX" 20 | S = S[:3] + S[3:] = "cbafedZYX" 21 | 翻转 S 得 S = "XYZdefabc" 22 | 23 | 对于 Python,使用切片即可。 24 | """ 25 | # write code here 26 | return s[n:] + s[:n] -------------------------------------------------------------------------------- /剑指offer/58-反转单词顺序/JZ58.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 牛客最近来了一个新员工 Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。 4 | 同事 Cat 对 Fish 写的内容颇感兴趣,有一天他向 Fish 借来翻看,但却读不懂它的意思。 5 | 例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。 6 | Cat 对一一的翻转这些单词顺序可不在行,你能帮助他么? 7 | """ 8 | 9 | class Solution: 10 | def ReverseSentence(self, s): 11 | """ 12 | 提示: 13 | 对于 C++ 可以先实现一个函数,以反转字符串的某一段,首先对整个字符串反转,再对每个单词反转。 14 | 对于 Python 直接将字符串通过空格分割成各个单词,将每个单词翻转后再拼接,再对拼接后的字符串翻转。 15 | """ 16 | # write code here 17 | if not s: 18 | return s 19 | 20 | words = s.split() 21 | # 当 s 只由空格组成,此时 words 为空 22 | if not words: 23 | return s 24 | 25 | res = "" 26 | for word in words: 27 | res += word[::-1] + " " 28 | res = res[::-1] 29 | # 最后一个单词后不应该添加空格,实际上也添加了,翻转后字符串首部有空格 30 | res = res[1:] 31 | return res 32 | -------------------------------------------------------------------------------- /剑指offer/6-反向打印链表/6 printListFromTailToHead.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 输入一个链表,按链表值从尾到头的顺序返回一个 ArrayList。 4 | """ 5 | 6 | # class ListNode: 7 | # def __init__(self, x): 8 | # self.val = x 9 | # self.next = None 10 | 11 | class Solution: 12 | # 返回从尾部到头部的列表值序列,例如[1,2,3] 13 | def printListFromTailToHead(self, listNode): 14 | """ 15 | 剑指 offer 里只说要逆序打印链表,这样用递归可以实现,因为递归本质上就是栈。 16 | 但牛客网里要求将逆序链表存到列表 ArrayList中并返回,就不太好用递归实现了。 17 | """ 18 | # write code here 19 | 20 | ArrayList = [] 21 | while listNode: 22 | ArrayList.insert(0, listNode.val) 23 | listNode = listNode.next 24 | return ArrayList 25 | -------------------------------------------------------------------------------- /剑指offer/6-反向打印链表/mainJZ6.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。 3 | * struct ListNode { 4 | * int val; 5 | * struct ListNode *next; 6 | * ListNode(int x) : 7 | * val(x), next(nullptr) { 8 | * } 9 | * }; 10 | */ 11 | class Solution { 12 | public: 13 | vector printListFromTailToHead(ListNode* head) { 14 | vector vec; 15 | if(head == nullptr) 16 | return vec; 17 | 18 | stack stk; 19 | ListNode* pNode = head; 20 | 21 | while(pNode) 22 | { 23 | stk.push(pNode); 24 | pNode = pNode->next; 25 | } 26 | 27 | while(!stk.empty()) 28 | { 29 | pNode = stk.top(); 30 | vec.push_back(pNode->val); 31 | stk.pop(); 32 | } 33 | return vec; 34 | } 35 | }; -------------------------------------------------------------------------------- /剑指offer/7-重建二叉树/JZ7.cpp: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 题目: 4 | * 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。 5 | * 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 6 | * 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 7 | */ 8 | 9 | /** 10 | * Definition for binary tree 11 | * struct TreeNode { 12 | * int val; 13 | * TreeNode *left; 14 | * TreeNode *right; 15 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 16 | * }; 17 | */ 18 | 19 | /** 20 | 提示: 21 | 知道前序遍历 pre = [1,2,4,7,3,5,6,8],则根节点的值必然是 pre[0], 22 | 由于中序遍历会以根节点把树分成左右两部分,所以找到 pre[0] 在中序遍历列表中的位置(设为 p), 23 | 就可以以 p 为分界线分别找到左右子树的前序中序序列。 24 | 25 | :param pre: 前序遍历序列 26 | :param tin: 中序遍历序列 27 | :return: 树根节点 28 | */ 29 | class Solution 30 | { 31 | public: 32 | TreeNode *reConstructBinaryTree(vector pre, vector vin) 33 | { 34 | if (pre.empty() || vin.empty()) 35 | return nullptr; 36 | int rootValue = pre[0]; 37 | TreeNode *tree = new TreeNode(rootValue); 38 | vector::iterator itIndex = find(vin.begin(), vin.end(), rootValue); 39 | int index = itIndex - vin.begin(); 40 | vector left_pre(pre.begin() + 1, pre.begin() + index + 1); 41 | vector left_vin(vin.begin(), vin.begin() + index); 42 | vector right_pre(pre.begin() + index + 1, pre.end()); 43 | vector right_vin(vin.begin() + index + 1, vin.end()); 44 | tree->left = reConstructBinaryTree(left_pre, left_vin); 45 | tree->right = reConstructBinaryTree(right_pre, right_vin); 46 | return tree; 47 | } 48 | }; -------------------------------------------------------------------------------- /剑指offer/7-重建二叉树/reConstructBinaryTree.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。 4 | 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 5 | 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 6 | """ 7 | 8 | 9 | class TreeNode: 10 | def __init__(self, x): 11 | self.val = x 12 | self.left = None 13 | self.right = None 14 | 15 | 16 | class Solution: 17 | # 返回构造的TreeNode根节点 18 | def reConstructBinaryTree(self, pre, tin): 19 | """ 20 | 提示: 21 | 知道前序遍历 pre = [1,2,4,7,3,5,6,8],则根节点的值必然是 pre[0], 22 | 由于中序遍历会以根节点把树分成左右两部分,所以找到 pre[0] 在中序遍历列表中的位置(设为 p), 23 | 就可以以 p 为分界线分别找到左右子树的前序中序序列。 24 | 25 | :param pre: 前序遍历序列 26 | :param tin: 中序遍历序列 27 | :return: 树根节点 28 | """ 29 | # write code here 30 | 31 | if pre and tin: 32 | tree = TreeNode(pre[0]) 33 | p = tin.index(pre[0]) # 下标 p 将 tin 分成左子树和右子树两部分 34 | # 找到每一个子数的 root 节点的下标,再将其分为左子树和右子树 35 | tree.left = self.reConstructBinaryTree(pre[1:p+1], tin[:p]) 36 | tree.right = self.reConstructBinaryTree(pre[p+1:], tin[p+1:]) 37 | return tree 38 | 39 | -------------------------------------------------------------------------------- /剑指offer/8-二叉树的下一个节点/getNext.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 题目: 4 | 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。 5 | 注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 6 | """ 7 | 8 | # class TreeLinkNode: 9 | # def __init__(self, x): 10 | # self.val = x 11 | # self.left = None 12 | # self.right = None 13 | # self.next = None 14 | 15 | 16 | class Solution: 17 | def getNext(self, pNode): 18 | """ 19 | 提示: 20 | 分为两大类: 21 | 1、有右子树的,那么下个结点就是右子树最左边的节点; 22 | 2、没有右子树的,也可以分成两类: 23 | a) 是父节点左孩子,那么父节点就是下一个节点 ; 24 | b) 是父节点的右孩子,找他的父节点的父节点的父节点...直到当前结点是其父节点的左孩子。 25 | 如果没有,那么他就是尾节点。 26 | """ 27 | # write code here 28 | if not pNode: 29 | return None 30 | if pNode.right: # 若有右子树 31 | tmp = pNode.right 32 | while tmp.left: # 找右子树最左边的节点 33 | tmp = tmp.left 34 | return tmp 35 | else: # 若无右子树 36 | tmp = pNode.next 37 | while tmp: # 若没有退到根节点,毕竟 root.next = None 38 | if pNode == tmp.left: # 是父节点左孩子,那么父节点就是下一个节点 39 | return tmp 40 | else: 41 | tmp = tmp.next # 是父节点的右孩子,找他的父节点的父节点的父节点...直到当前结点是其父节点的左孩子 42 | pNode = pNode.next 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /剑指offer/8-二叉树的下一个节点/详细解析.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinbooooom/coding-for-algorithms/889d8fa489f1f2719c5a0dafd3ae51df7b4bf978/剑指offer/8-二叉树的下一个节点/详细解析.PNG -------------------------------------------------------------------------------- /剑指offer/9-用两个栈实现队列/JZ9.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。 队列中的元素为 int 类型。 3 | */ 4 | 5 | class Solution 6 | { 7 | public: 8 | void push(int node) 9 | { 10 | stack1.push(node); 11 | } 12 | 13 | int pop() 14 | { 15 | if (stack2.empty()) 16 | { 17 | while (!stack1.empty()) 18 | { 19 | int data = stack1.top(); 20 | stack2.push(data); 21 | stack1.pop(); 22 | } 23 | } 24 | // 将 stack1 里的数据放入栈 stack2 后,stack2还是空的, 25 | // 说明 stack1 本身就是空的,此时就不能出队了,应该报错 26 | if (stack2.empty()) 27 | cout << "queue is empty" << endl; 28 | int data = stack2.top(); 29 | stack2.pop(); 30 | return data; 31 | } 32 | 33 | private: 34 | stack stack1; // 队尾,进队 35 | stack stack2; // 队头,出队 36 | }; 37 | -------------------------------------------------------------------------------- /剑指offer/9-用两个栈实现队列/stack2queue.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 4 | """ 5 | 6 | 7 | class Solution: 8 | def __init__(self): 9 | self.stack1 = [] # 用于压入 10 | self.stack2 = [] # 用于弹出 11 | 12 | def push(self, node): 13 | # write code here 14 | self.stack1.append(node) 15 | 16 | def pop(self): 17 | """ 18 | 提示: 19 | 栈只能先入先出,而队列是先入后出。如果 stack1 非空,stack2 为空, 20 | 队列执行出队操作时,把 stack1 的元素 pop 出来存到 stack2 中, 21 | 在 stack2 中执行 pop 操作就类似于出队操作了。 22 | """ 23 | # return xx 24 | if not self.stack2: 25 | while self.stack1: 26 | self.stack2.append(self.stack1.pop()) 27 | if self.stack2: 28 | return self.stack2.pop() 29 | --------------------------------------------------------------------------------