数据结构与算法
文章平均质量分 82
总结力扣常见题型
weixin_39770712
这个作者很懒,什么都没留下…
展开
-
手撕力扣之动态规划4:让字符串成为回文串的最少插入次数
动态规划原创 2022-06-04 16:28:27 · 207 阅读 · 0 评论 -
手撕力扣之链表2:奇偶链表、排序奇升偶降链表
力扣328. 奇偶链表给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。class Solution {public: ListNode* oddEvenList(ListNode* head) { if (head == nullptr) { return head; } ListNode* evenHead = head->ne原创 2022-01-11 06:57:45 · 492 阅读 · 0 评论 -
手撕力扣之图论:课程表、课程表 II、省份数量、等式方程的可满足性、情侣牵手、 实现 Trie (前缀树)、数组中两个数的最大异或值、判断二分图
力扣210. 课程表 II现在你总共有 n 门课需要选,记为 0 到 n-1。在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]。给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。思路:我们使用一个队列来进行广度优先搜索。开始时,所有入度为 00 的节点都被放入队列中,它们就是可以作为拓扑排序最前面的节点,并且它原创 2021-08-19 15:05:32 · 282 阅读 · 0 评论 -
手撕力扣之哈希法.下:最长连续序列、LRU 缓存机制、 LFU 缓存、连续的子数组和
力扣128. 最长连续序列给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。思路:由于我们要枚举的数 x 一定是在数组中不存在前驱数 x−1 的,不然按照上面的分析我们会从 x−1 开始尝试匹配,因此我们每次在哈希表中检查是否存在 x−1 即能判断是否需要跳过了。class Solution {public: int longestConsecutive(vector<int>& nums) { unor转载 2021-05-13 10:57:53 · 155 阅读 · 0 评论 -
手撕力扣之数学题:用 Rand7() 实现 Rand10()、会议室 II、对角线遍历I和II、可怜的小猪、数据流的中位数
力扣470. 用 Rand7() 实现 Rand10()腾讯面试高频题。定理:若rand_n()能等概率生成1到n的随机整数,则有(rand_n() - 1) * n + rand_n()能 等概率生成1到n * n的随机整数。解释: rand()7能等概率生成1~7, rand7() - 1能等概率生成0~6, (rand7() - 1) * 7能等概率生成{0, 7, 14, 21, 28, 35, 42}, (rand7() - 1) * 7 + rand7()能等概率生原创 2021-04-24 09:59:16 · 172 阅读 · 0 评论 -
手撕力扣之栈:下一个更大元素 I、下一个更大元素 II、132 模式、和至少为 K 的最短子数组
力扣042. 接雨水给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。int trap(vector<int>& height){ if (height == null) return 0; int ans = 0; int size = height.size(); vector<int> left_max(size), right_max(size); left_原创 2021-04-07 15:06:46 · 131 阅读 · 0 评论 -
手撕力扣之动态规划:最长公共子序列、杨辉三角、接雨水、字符串相乘、解码方法、把数字翻译成字符串、正则表达式匹配、通配符匹配、最大子矩阵、不同路径 II、最长回文子序列、下降路径最小和、圆环回原点问题
力扣1143. 最长公共子序列给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。若这两个字符串没有公共子序列,则返回 0。思路:class Solution {p转载 2021-03-08 14:09:27 · 364 阅读 · 0 评论 -
手撕力扣之dfs(树):完全二叉树的节点个数、求根到叶子节点数字之和、二叉树中的最大路径和、打家劫舍III、二叉树的序列化与反序列化、二叉树中所有距离为K的结点
力扣222. 完全二叉树的节点个数给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h 个节点。思路:class Solution {public: int depth(TreeNode* root) { int ans=0; while(root原创 2021-02-24 12:04:24 · 273 阅读 · 0 评论 -
手撕力扣之双指针(字符串、数组):比较版本号、长度最小的子数组、最小覆盖子串、 有序数组的平方、压缩字符串、有效三角形的个数、区间列表的交集、无重叠区间、最小区间、反转字符串中的单词 III
力扣165. 比较版本号给你两个版本号 version1 和 version2 ,请你比较它们。版本号由一个或多个修订号组成,各修订号由一个 ‘.’ 连接。每个修订号由 多位数字 组成,可能包含 前导零 。每个版本号至少包含一个字符。修订号从左到右编号,下标从 0 开始,最左边的修订号下标为 0 ,下一个修订号下标为 1 ,以此类推。例如,2.5.33 和 0.1 都是有效的版本号。比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较 忽略任何前导零后的整数值 。也就是说,修订转载 2021-02-03 16:43:39 · 391 阅读 · 0 评论 -
手撕力扣之dfs(非二叉树):括号生成、单词搜索、复原IP地址、二叉搜索树的后序遍历序列、矩阵中的最长递增路径、岛屿数量、岛屿的最大面积、至少有 K 个重复字符的最长子串
力扣337. 打家劫舍 III在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。思路:和打家劫舍I一样,不能选择相邻的两个节点。所以对于一个子树来说,有两种情况:包含当前根节点不包含当前根节原创 2021-01-09 22:09:36 · 320 阅读 · 0 评论 -
手撕力扣之排序:排序数组、数组中的逆序对、排序链表、最小的k个数、数组中的第K个最大元素、前 K 个高频元素、根据身高重建队列、最大数、下一个排列、下一个更大元素 III、最大交换、字典序的第K小数字
力扣剑指 Offer 40. 最小的k个数输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。class Solution {public: vector<int> getLeastNumbers(vector<int>& arr, int k) { //最大堆:就是由大到小 priority_queue<int> max_Heap;原创 2020-12-12 15:35:15 · 399 阅读 · 0 评论 -
手撕力扣之数学题:整数反转、回文数、Excel表列序号、阶乘后的零、各位相加、自除数、分糖果 II、3的幂、Nim 游戏、1比特与2比特字符、圆圈中最后剩下的数字、三个数的最大乘积、有效的正方形
力扣258. 各位相加给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。class Solution {public: int addDigits(int num) { while (num > 9) { int sum = 0; while (num) { int tmp = num % 10; su转载 2020-12-10 20:32:12 · 401 阅读 · 0 评论 -
手撕力扣之二分(下篇):x 的平方根、寻找峰值、寻找两个正序数组的中位数、山脉数组中查找目标值、最长递增子序列、俄罗斯套娃信封问题、分割数组的最大值
力扣162. 寻找峰值峰值元素是指其值大于左右相邻值的元素。给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。你可以假设 nums[-1] = nums[n] = -∞。思路:为什么二分查找大的那一半一定会有峰值呢?(即nums[mid]<nums[mid+1]时,mid+1~N一定存在峰值) 我的理解是,首先已知 nums[mid+1]>nums[mid],那么mid+原创 2020-12-07 20:32:37 · 339 阅读 · 0 评论 -
手撕力扣之位运算:两整数之和、只出现一次的数字(I、 II)、丢失的数字、汉明距离、数字的补数、二进制中1的个数、Pow(x, n)、数组中数字出现的次数、数组中数字出现的次数 II、求1+2+…+n
力扣136. 只出现一次的数字给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。1.交换律:a ^ b ^ c <=> a ^ c ^ b2.任何数于0异或为任何数 0 ^ n => n3.相同的数异或为0: n ^ n => 0class Solution {public: int singleNumber(vector<int>& nums) { int res=0;原创 2020-11-19 20:18:57 · 263 阅读 · 0 评论 -
手撕力扣之双指针【链表数组】:删除链表的倒数第N个节点、链表中倒数第k个节点、分隔链表、环形链表I、II、寻找重复数、颜色分类、最短无序连续子数组、和为s的连续正数序列、翻转字符串里的单词、验证回文串
力扣019. 删除链表的倒数第N个节点class Solution {public: ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode* dummyHead = new ListNode(0); dummyHead->next = head; ListNode* slow = dummyHead; ListNode* fast = dummyHead;原创 2020-11-18 21:23:55 · 330 阅读 · 0 评论 -
手撕力扣之动态规划:爬楼梯、不同路径、最小路径和、三角形最小路径和、买卖股票的最佳时机、打家劫舍1和2、最小花费爬楼梯、礼物的最大价值、剪绳子、连续子数组的最大和、乘积最大子数组、单词拆分、最大正方形
力扣120. 三角形最小路径和DP自下向上(二位数组)class Solution {public: int minimumTotal(vector<vector<int>>& triangle) { // 行数 int n = triangle.size(); // 从倒数第二行开始 for (int i = n - 2; i >= 0; i--) {原创 2020-11-09 20:12:09 · 306 阅读 · 0 评论 -
手撕力扣动态规划:分割等和子集、零钱兑换12、完全平方数、比特位计数、丑数 II、超级丑数、最长回文子串、回文子串、最长重复子数组、字符串相加、36进制加法、编辑距离、 买卖股票的最佳时机34
力扣416. 分割等和子集只有确定了如下四点,才能把背包问题,套到本题上来。1.背包的体积为sum / 22.背包要放入的商品(集合里的元素)体积为 元素的数值,价值也为元素的数值3.背包如何正好装满,说明找到了总和为 sum / 2 的子集。4.背包中每一个元素一定是不可重复放入。定义里数组为dp[],dp[i] 表示 背包中放入体积为i的商品,最大价值为dp[i]。套到本题,dp[i]表示 背包中总和是i,最大可以凑成总和为i的元素总和为dp[i]。dp[i]一定是小于等于i的,因为背包不能转载 2020-11-09 19:11:20 · 321 阅读 · 0 评论 -
手撕力扣之数组题:旋转图像、螺旋矩阵I II、加一、多数元素、旋转数组、除自身以外数组的乘积、 找到所有数组中消失的数字、和为K的子数组、把数组排成最小的数、扑克牌中的顺子、递增的三元子序列、矩阵置零
力扣054. 螺旋矩阵1.首先设定上下左右边界2.其次向右移动到最右,此时第一行因为已经使用过了,可以将其从图中删去,体现在代码中就是重新定义上边界3.判断若重新定义后,上下边界交错,表明螺旋矩阵遍历结束,跳出循环,返回答案4.若上下边界不交错,则遍历还未结束,接着向下向左向上移动,操作过程与第一,二步同理5.不断循环以上步骤,直到某两条边界交错,跳出循环,返回答案class Solution {public: vector<int> spiralOrder(vector&原创 2020-11-08 18:16:55 · 345 阅读 · 0 评论 -
手撕力扣之二分上篇:二分查找、0~n-1中缺失的数字、搜索插入位置、搜索旋转排序数组、搜索旋转排序数组 II、寻找旋转排序数组中的最小值、寻找旋转排序数组中的最小值 II、在排序数组中查找元素首末位置
力扣035.搜索插入位置四种可能的情况:1.目标值在数组所有元素之前 2.目标值等于数组中某一个元素3.目标值插入数组中的位置 4.目标值在数组所有元素之后区间为前闭后闭class Solution {public: int searchInsert(vector<int>& nums, int target) { int n = nums.size(); int left = 0; int right = n -原创 2020-11-08 14:11:17 · 232 阅读 · 0 评论 -
手撕力扣之贪心法:买卖股票的最佳时机 II、最大子序和、跳跃游戏、跳跃游戏 II、分发饼干、划分字母区间、重构字符串、分发糖果、种花问题、加油站
力扣053. 最大子序和class Solution {public: int maxSubArray(vector<int>& nums) { int result = INT32_MIN; int count = 0; for (int i = 0; i < nums.size(); i++) { count += nums[i]; if (count > resu原创 2020-11-05 19:42:27 · 231 阅读 · 0 评论 -
c++中to_string、stoi()、atoi()使用
1、to_string包含在# include< string >。作用是把数值类型如int、double、long等转化为stringint a = 4;double b = 3.14;string str1, str2;str1 = to_string(a);str2 = to_string(b);cout << str1 << endl;cout << str2 << endl;2、stoi和atoi包含在#includ原创 2020-10-30 19:51:33 · 786 阅读 · 0 评论 -
手撕力扣之回溯题【子集、组合、排列问题】:子集、子集 II、组合、组合总和、组合总和 II、组合总和 III、电话号码的字母组合、全排列、全排列 II、字符串的排列、分割回文串、复原IP地址
力扣077.组合树状图:class Solution {private: vector<vector<int>> result; vector<int> path; void backtracking(int n, int k, int startIndex) { if (path.size() == k) { result.push_back(path); return;原创 2020-10-29 19:32:47 · 287 阅读 · 0 评论 -
手撕力扣之双指针:无重复字符的最长子串、 盛最多水的容器、删除排序数组中的重复项I、II、替换空格、合并区间、移动零、二维数组中的查找、和为s的两个数字、调整顺序使奇数位于偶数前面、最大连续1的个数3
力扣026. 删除排序数组中的重复项给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。class Solution {public: int removeDuplicates(vector<int>& nums) { if (nums.empty()) return 0; // 别忘记空数组的判断原创 2020-10-28 19:31:19 · 367 阅读 · 0 评论 -
手撕力扣之哈希法.上:宝石与石头、字母异位词分组、快乐数、存在重复元素、数组中重复的数字、两个数组的交集、有效的字母异位词、分糖果、第一个只出现一次的字符、最长回文串、缺失的第一个正数
力扣202. 快乐数当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。判断sum是否重复出现就可以使用unordered_set。class Solution {public: // 取数值各个位上的单数之和 int getSum(int n) { int sum = 0; while (n) {原创 2020-10-27 20:13:21 · 218 阅读 · 0 评论 -
手撕代码之n数之和:两数之和、三数之和、最接近的三数之和、四数之和、四数相加 II、两数相加、两数相加 II
力扣001. 两数之和class Solution {public: vector<int> twoSum(vector<int>& nums, int target) { std::unordered_map <int,int> map; for(int i = 0; i < nums.size(); i++) { auto iter = map.find(target - nums[i]原创 2020-10-26 20:51:01 · 266 阅读 · 0 评论 -
手撕力扣之链表:删除链表中的节点、 删除链表的节点、移除链表元素、相交链表、两两交换链表中的节点、删除排序链表中的重复元素I、II、旋转链表、重排链表、合并K个升序链表、复制带随机指针的链表
力扣203. 移除链表元素直接使用原来的链表来进行删除操作:class Solution {public: ListNode* removeElements(ListNode* head, int val) { // 删除头结点 while (head != NULL && head->val == val) { // 注意这里不是if ListNode* tmp = head; head原创 2020-10-26 20:02:48 · 251 阅读 · 0 评论 -
手撕力扣之字符串:KMP算法、最长公共前缀、字符串变形、旋转字符串、字符串转换整数 (atoi)、验证IP地址、字符串相乘、删除字符串中的所有相邻重复项
力扣028. 实现 strStr()构造next数组其实就是计算模式串s,前缀表的过程。 主要有如下三步:初始化处理前后缀不相同的情况处理前后缀相同的情况void getNext(int* next, const string& s){ int j = -1; next[0] = j; for(int i = 1; i < s.size(); i++) { // 注意i从1开始 while (j >= 0 && s[i]原创 2020-10-25 18:19:41 · 373 阅读 · 0 评论 -
手撕力扣之栈:最小栈、用栈实现队列、用两栈实现队列、用队列实现栈、有效括号、逆波兰表达式求值、字符串解码、栈的压入、弹出序列、基本计算器 II、I、每日温度、滑动窗口最大值、移掉K位数字、最长有效括号
力扣232. 用栈实现队列使用栈实现队列的下列操作:push(x) – 将一个元素放入队列的尾部。pop() – 从队列首部移除元素。peek() – 返回队列首部的元素。empty() – 返回队列是否为空。class MyQueue {public: stack<int> stIn; stack<int> stOut; /** Initialize your data structure here. */ MyQueue() {原创 2020-10-25 10:13:48 · 349 阅读 · 0 评论 -
手撕力扣之二叉搜索树:不同的二叉搜索树(I、II)、验证二叉搜索树、把二叉搜索树转换为累加树、将有序数组转换为二叉搜索树、二叉搜索树的第k大/小节点、有序链表转换二叉搜索树、二叉搜索树与双向链表
力扣098. 验证二叉搜索树:中序遍历【递归】详解初始设置为一个最小值来比较:class Solution {public: long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值 bool isValidBST(TreeNode* root) { if (root == NULL) return true; bool left = isValidBST(root->left); // 中原创 2020-10-24 19:26:09 · 151 阅读 · 0 评论 -
手撕力扣之构造二叉树:从中序与后序遍历序列构造二叉树、从前序与中序遍历序列构造二叉树、根据前序和后序遍历构造二叉树、最大二叉树
力扣106.从中序与后序遍历序列构造二叉树思路:第一步:如果数组大小为零的话,说明是空节点了。第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)第五步:切割后序数组,切成后序左数组和后序右数组第六步:递归处理左区间和右区间class Solution {private: // 中序区间:[inorderBegin, inord原创 2020-10-23 20:51:59 · 152 阅读 · 0 评论 -
手撕力扣之dfs(树): 二叉树的最近公共祖先、二叉搜索树的最近公共祖先、二叉树的最大深度、合并二叉树、平衡二叉树、路径总和、路径总和II、另一个树的子树、树的子结构、二叉树的直径、二叉树展开为链表
力扣236. 二叉树的最近公共祖先:【递归与回溯】详解解题思路:完整版:class Solution {public: TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { if (root == q || root == p || root == NULL) return root; TreeNode* left = lowestCommonAncestor(r原创 2020-10-21 20:24:57 · 247 阅读 · 0 评论 -
手撕力扣之翻转题:反转链表、反转链表 II、从尾到头打印链表、K 个一组翻转链表、回文链表、翻转二叉树、左旋转字符串
力扣206. 反转链表反转一个单链表。双指针法:class Solution {public: ListNode* reverseList(ListNode* head) { ListNode* temp; // 保存cur的下一个节点 ListNode* cur = head; ListNode* pre = NULL; while(cur) { temp = cur->next; // 保存一原创 2020-10-19 19:35:22 · 312 阅读 · 0 评论 -
手撕力扣之层序遍历:二叉树的层次遍历I、II、二叉树的右视图、二叉树的锯齿形层次遍历、判断一棵二叉树是否为完全二叉树、二叉树最大宽度、二叉树的完全性检验、N叉树的层序遍历
力扣102.二叉树的层序遍历给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。class Solution {public: vector<vector<int>> levelOrder(TreeNode* root) { queue<TreeNode*> que; if (root != NULL) que.push(root); vector<vector&l原创 2020-10-18 22:16:41 · 151 阅读 · 0 评论 -
手撕力扣:对称二叉树;二叉树的前序、中序、后序遍历的递归/迭代解法
力扣101.对称二叉树给定一个二叉树,检查它是否是镜像对称的。对称二叉树(递归法)class Solution {public: bool isSymmetric(TreeNode* root) { if(!root) return true; return isEqual(root->left,root->right); } bool isEqual(TreeNode* p,TreeNode* q) {原创 2020-10-18 10:08:12 · 397 阅读 · 0 评论 -
二分查找算法详解
二分查找算法详解 本文主要探究几个最常用的二分查找场景:寻找一个数、寻找左侧边界、寻找右侧边界。 而且,我们就是要深入细节,比如while循环中的不等号是否应该带等号,mid 是否应该加一等等。分析这些细节的差异以及出现这些差异的原因,保证你能灵活准确地写出正确的二分查找算法。二分查找的框架int binarySearch(int[] nums, int target) { int left = 0, right = ...; while(...) {原创 2020-09-30 15:34:37 · 144 阅读 · 0 评论