LeetCode刷题记录
开始刷题啦,动脑又动手
星-耀
A platform for communication
展开
-
27. 移除元素(双指针)
解法:双指针相似题:int removeElement(int* nums, int numsSize, int val){ int left = 0, right = 0; while(right < numsSize) { if(nums[right] != val) { nums[left++] = nums[right++]; } else right++; } ..原创 2021-09-14 19:00:48 · 186 阅读 · 0 评论 -
1894. 找到需要补充粉笔的学生编号(int溢出)
当kkk很大,远远超过chalkchalkchalk数组的和totaltotaltotal时,应该对totaltotaltotal取余,减少我们寻找的轮次。取余后,k<totalk<totalk<total,我们只需遍历一次就能找出需要补充粉笔的学生编号。其中,有一个问题就是,当数组中的数字很大时,其和totaltotaltotal可能会超出intintint范围。解决办法是用long longlong\ longlong long类型来保存求和结果。int c.原创 2021-09-10 12:18:58 · 188 阅读 · 0 评论 -
剑指 Offer 53 - II. 0~n-1中缺失的数字(二分法)
解法一:遍历int missingNumber(int* nums, int numsSize){ for(int i=0; i<numsSize; i++) { if(nums[i]!=i) return i; } return numsSize;}时间复杂度O(n)O(n)O(n),空间复杂度O(1)O(1)O(1)。解法二:二分对于有序数据,最好使用二分法来查找。如果mid位置的值等于mid,说明左半区间不缺值,应该在右半区间去找。.原创 2021-09-09 21:06:19 · 254 阅读 · 2 评论 -
剑指 Offer 68 - II. 二叉树的最近公共祖先(递归)
解法:递归/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q.原创 2021-09-09 19:39:11 · 131 阅读 · 0 评论 -
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先(递归)
解法:递归/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q.原创 2021-09-09 17:56:49 · 111 阅读 · 0 评论 -
剑指 Offer 55 - II. 平衡二叉树(DFS)
解法:树的深度遍历先做这道题:剑指 Offer 55 - I. 二叉树的深度(递归)自底向上,比较每个节点左子树与右子树的高,相差不大于1,则为平衡二叉树。/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */int height(struct TreeNo.原创 2021-09-09 12:38:15 · 118 阅读 · 0 评论 -
剑指 Offer 54. 二叉搜索树的第k大节点(中序遍历)
解法:中序遍历首先,明确二叉搜索树的性质:(1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;(2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;(3)它的左、右子树也是二叉搜索树。(4)它的中序遍历结果是一个递增序列。在本题中,如果使用中序遍历的倒序,即右->根->左,会得到我们想要的递减序列。/** * Definition for a binary tree node. * struct TreeNode { * int val.原创 2021-09-08 16:37:07 · 133 阅读 · 0 评论 -
剑指 Offer 58 - I. 翻转单词顺序(双指针)
解法:原地翻转思路:第一步,将首部和中间多余空格移到字符串尾部。第二步,将字符串(不含尾部空格)原地翻转,先局部翻转,再整体翻转。void swap(char *a, char *b){ char temp = *a; *a = *b; *b = temp;}char* reverseWords(char* s){ int total = strlen(s) + 1; // step1.快慢指针将首部和中间多余空格移到后面去 int slow .原创 2021-09-08 11:50:03 · 110 阅读 · 0 评论 -
剑指 Offer 58 - II. 左旋转字符串
解法一:字符串切分与拼接(使用辅助空间)(题目有限制,字符串长大于1,则不可能为空。同时,k小于字符串长,所以k不用取余。)先申请一块辅助空间,用于临时保存拼接后的字符串。从旋转的位置开始,把字符串分为2部分空间。先将第2部分放入辅助空间,再将第一部分放入,拼接完成。最后将拼接好的字符串放回原数组,并释放辅助空间。char* reverseLeftWords(char* s, int n){ int len = strlen(s); // 申请辅助空间,将原数组分区间放到temp数组.原创 2021-09-08 00:07:27 · 97 阅读 · 0 评论 -
剑指 Offer 55 - I. 二叉树的深度(递归)
解法:递归/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */int maxDepth(struct TreeNode* root){ if(!root) return 0; int left = maxDepth(root->left.原创 2021-09-07 20:30:48 · 110 阅读 · 0 评论 -
111. 二叉树的最小深度(递归)
解法:递归对比题:二叉树的高/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */int minDepth(struct TreeNode* root){ // 空树,返回0 if(!root) return 0; int left .原创 2021-09-07 20:20:52 · 111 阅读 · 0 评论 -
剑指 Offer 64. 求1+2+…+n(逻辑运算短路特性)
解法:递归 + 逻辑运算短路特性不限制的话,可以用迭代或递归解法。int sumNums(int n){ // 递归边界 if(n == 1) return 1; return n + sumNums(n-1);}但题目要求不能用循环和条件语句。使用逻辑运算短路特性代替条件判断:int sumNums(int n){ n && (n += sumNums(n-1)); return n;}...原创 2021-09-06 20:09:41 · 105 阅读 · 0 评论 -
剑指 Offer 61. 扑克牌中的顺子(排序)
解法:排序思路:如果有重复元素,则不可能构成顺子。没有重复元素,则最大牌减去最小牌(除了大小王)的值应该小于5。评论区图文解析void *cmp(void *a, void *b){ return *(int*)a - *(int*)b;}bool isStraight(int* nums, int numsSize){ // 排序 qsort(nums, numsSize, sizeof(int), cmp); int count = 0; for.原创 2021-09-06 19:39:08 · 176 阅读 · 0 评论 -
剑指 Offer 40. 最小的k个数(随机选择算法)
解法:随机选择算法随机选择算法建立在快排的基础上。/** * Note: The returned array must be malloced, assume caller calls free(). */ // 选择主元,进行分区 int partion(int *arr, int left, int right) { int temp = arr[left]; while(left < right) { while(left <.原创 2021-09-06 18:55:45 · 153 阅读 · 0 评论 -
剑指 Offer 56 - I. 数组中数字出现的次数(位运算+分组)
解法:分组进行位运算先做这道题136.只出现一次的数字从头到尾异或数组中的每个数字,那么最终得到的结果就是两个只出现1次的数字的异或结果。**由于这两个数字不一样,异或结果必然不为0,也就是说结果的二进制中存在至少1位为1,找到这个1的位置,我们可以根据该位是否为1将原数组分为两个子数组。**分类的目的是把这两个数分到不同的子数组。因为两个相同的数字的任意一位都是相同的,所以它们不会被分开,会同时出现在同一组。分成两个子数组后,每个子数组后包含一个只出现一次的数字,而其他数字都出现了两次。就将问题转.原创 2021-09-05 21:52:53 · 108 阅读 · 0 评论 -
剑指 Offer 25. 合并两个排序的链表
解法:迭代法如果知道归并排序的话,就很容易明白这道题的做法。/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){ // 用哑结点dummy管理排序后的链表 .原创 2021-09-05 20:17:13 · 69 阅读 · 0 评论 -
470. 用 Rand7() 实现 Rand10() (拒绝采样+进制转换)
解法:拒绝采样 + 进制转换思路:在拒绝采样中,如果生成的随机数满足要求,那么就返回该随机数,否则会不断生成,直到生成一个满足要求的随机数为止。我们只需要能够满足等概率的生成 10个不同的数即可,具体的生成方法可以有很多种。自古评论区出人才:通过两次独立的随机过程,生成两个随机数a和b,将其看做两个7进制数,它们一共可以表示0~48范围内的数,这49个数中每个数的生成概率都是相等的,取前10个就可以满足要求。// The rand7() API is already defined for yo.原创 2021-09-05 19:49:06 · 138 阅读 · 0 评论 -
剑指 Offer 14- II. 剪绳子 II(数学+快速幂求余)
在剪绳子1的基础上,加入了快速幂取余。// 快算幂计算过程中使用long long, 避免int溢出long long myPow(long long base, long long p, int mod){ long long ret = 1; while(p) { if(p&1) { ret = ret * base % mod; } p = p>>1; .原创 2021-09-05 15:20:23 · 105 阅读 · 0 评论 -
剑指 Offer 14- I. 剪绳子(数学)
评论区题解:剪绳子(含数学推导)记住两个结论:(1)将绳子等分,得到的乘积最大。(2)最优段长为3。int cuttingRope(int n){ if (n<=3) return n-1; // 当n>3时,有三种情况 int residue = n%3; int count = n/3; if(residue == 2) return pow(3, count)*2; else if(residue == 1) return pow.原创 2021-09-04 21:25:25 · 101 阅读 · 0 评论 -
557. 反转字符串中的单词 III (双指针)
解法:双指针在c中,字符串是用字符数组来保存的,可以修改(除了常量字符串)。思路:找到每个单词的边界,对每个单词进行逆序处理。void swap(char *a, char *b){ char temp = *a; *a = *b; *b = temp;}void reverseWord(char *s, int left, int right){ // 同向双指针用来逆序单个单词 int p = left, q = right; while.原创 2021-09-02 17:13:36 · 148 阅读 · 0 评论 -
剑指 Offer 11. 旋转数组的最小数字(二分法)
解法:二分法查看官方题解要画图理解各种情况,接下来照搬三张官方图:int minArray(int* numbers, int numbersSize){ int left = 0, right = numbersSize - 1; while(left < right) { int mid = left + (right - left)/2; if(numbers[mid] > numbers[right]) left = m.原创 2021-09-01 16:32:44 · 105 阅读 · 0 评论 -
剑指 Offer 53 - I. 在排序数组中查找数字 I(两次二分查找)
初始解法:二分查找+线性搜索思路:通过二分查找定位到target位置,以此为起点,向两边线性搜索target并统计次数。int binarySearch(int *nums, int left, int right, int target){ while(left <= right) { int mid = left + (right-left)/2; if(nums[mid] == target) return mid; els.原创 2021-09-01 15:17:23 · 93 阅读 · 0 评论 -
剑指 Offer 32 - II. 从上到下打印二叉树 II(BFS,层序遍历)
解法:BFS和一般的BFS相比,多了区分层次的要求。只需要出队前,记录当前队列的大小,即当前层的元素个数,然后一次性取出一层就好了。在取出单个元素的时候,和普通的BFS没有区别。使用C++现成的queue数据结构。/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(i.原创 2021-09-01 11:50:25 · 97 阅读 · 0 评论 -
剑指 Offer 32 - I. 从上到下打印二叉树(BFS,层序遍历)
解法:BFS要使用队列来辅助。就用STL中现成的queue吧。记得对输入进行检查,如果root为空,直接返回空数组。/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; *.原创 2021-09-01 11:22:46 · 100 阅读 · 0 评论 -
101. 对称二叉树(递归)
解法:递归什么是镜像?对于两个待比较的节点ppp,qqq。若p和q空,定义为对称;若p和q只有一个空,则不对称;若p和q都不为空,镜像对称需满足以下条件:(1)p和q的值应相等。(2)p的左孩子的值和q的右孩子的值相等。(2)p的右孩子的值和q的左孩子的值相等。/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * .原创 2021-09-01 10:52:03 · 83 阅读 · 0 评论 -
2. 两数相加(大数加法)
解法:加法模拟技巧:对于链表,可申请哑节点(dummy),便于管理头节点。加法过程:相应位的和用一个数temptemptemp临时保存。在这过程中会用到两个值,一个是当前位的非进位和,可以用temp%10temp\%10temp%10;另一个是进位,可以用temp/10temp/10temp/10得到。最后,加法做完后,如果进位不为0,直接赋给最高位(当前最高位的下一位)。/** * Definition for singly-linked list. * struct ListNode {..原创 2021-09-01 00:08:35 · 170 阅读 · 0 评论 -
剑指 Offer 07. 重建二叉树(递归)
解法:递归算法过程/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ struct TreeNode* newTreeNode(int val) { struct TreeNode *root = malloc(sizeof(struct Tr.原创 2021-08-31 19:21:54 · 75 阅读 · 0 评论 -
剑指 Offer 16. 数值的整数次方(快速幂)
解法:快速幂算法解析要考虑到特殊值和边界条件。特殊值:(1)底数为0,且指数为0,000^000没有意义,约定结果为1。00=10^0=100=1(2)底数为0,且指数不为0,结果为0。0n=00^n=00n=0(3)底数为1,且指数为任意值,结果为1。1n=11^n=11n=1(4)底数不为0,且指数为0,结果为1。x0=1x^0=1x0=1边界值:(1)题目要求不考虑大数问题。忽略底数的边界。(2)指数为负数时,可以先对指数求绝对值,再把底数取倒数。问题在于当指数n=−2.原创 2021-08-31 11:44:03 · 99 阅读 · 0 评论 -
剑指 Offer 10- II. 青蛙跳台阶问题(动态规划)
解法:动态规划如何想到该解法,参考评论区图解,个人觉得很好理解。得到最终的递推公式f(n)=f(n−1)+f(n−2)f(n)=f(n-1)+f(n-2)f(n)=f(n−1)+f(n−2)这不就是斐波那契数列公式吗?迭代解法如下:int numWays(int n){ if(n==0 || n==1) return 1; int a = 1, b = 1; for(int i = 2; i<=n; i++) { b = a + .原创 2021-08-30 21:26:08 · 89 阅读 · 0 评论 -
剑指 Offer 04. 二维数组中的查找(二分查找)
解法一:暴力解法(略)时间复杂度O(n2)O(n^2)O(n2),显然不算高效。解法二:线性二分查找对数组的每一行做二分查找,时间复杂度O(nlogm)O(nlogm)O(nlogm)。不够好。解法三:二维二分查找线性二分查找的特点是,每次查找都能确定目标数据区间,缩小一半查找范围。对本题来说,可以从右上角或者左下角开始查找,可以实现缩小查找范围的效果。查找起始点:(1)左上角,所有数据都比它大,无法缩小查找范围。(2)右下角,所有数据都比它小,无法缩小查找范围。(3)左下角,右边数据.原创 2021-08-30 19:19:45 · 359 阅读 · 0 评论 -
剑指 Offer 03. 数组中重复的数字(哈希表,原地哈希)
解法:哈希表哈希映射:将数字nums[i]nums[i]nums[i]放到nums[nums[i]]nums[nums[i]]nums[nums[i]]的位置。处理完后,数组中的数字应与其索引相等。如果不满足该映射,则该元素为重复的元素。题目只要求找出任意一个重复元素,所以遇到任意一个重复元素就返回了。扩展:如果要找出所有重复元素,或者要找最小的重复元素?需要完整的遍历整个数组,对所有元素进行哈希映射。之后再进行重复元素的判断。本题C代码:void swap(int *a, int *b){.原创 2021-08-30 16:22:08 · 208 阅读 · 0 评论 -
剑指 Offer 09. 用两个栈实现队列
思路:一个add栈负责添加元素,一个del栈负责删除元素。(1)加入元素:直接向add栈添加(2)删除元素:需要判断del栈的状态。若del栈空,且add栈空,则没有要删除的元素。若del栈空,且add栈非空,则将add栈的元素出栈然后压入del栈,此时del栈栈顶元素就是队首元素。除了前两种情况,则del栈非空,del栈栈顶元素直接出栈。#define STACKMAXSIZE 10000typedef struct { int *baseAdd; int *baseDe.原创 2021-08-30 10:37:00 · 89 阅读 · 0 评论 -
剑指 Offer 05. 替换空格(字符串处理)
思路:遍历原字符串统计空格个数,以计算替换空格后字符串所占空间大小,并分配内存。然后遍历原字符串,对新字符串进行赋值。对于非空格字符,直接拷贝;对空格进行相应替换。记得在末尾加上字符串结束标志。char* replaceSpace(char* s){ // 统计空格个数 int countSpace = 0; for(int i=0; i<strlen(s); i++) { if(s[i] == ' ') countSpace++; } .原创 2021-08-29 20:27:46 · 89 阅读 · 0 评论 -
剑指 Offer 50. 第一个只出现一次的字符(哈希表)
解法:哈希表思路:遍历字符串两次。第一次遍历,统计每个字符在字符串中出现的频度。第二次遍历,找出出现次数为1的第一个字符。哈希表查找效率高,查找的时间复杂度为O(1)O(1)O(1)。如何构建哈希表?因为字符串只含小写字母,一共有26个小写字母。可以将小写字母映射为一个26进制数,作为哈希表的索引。// 将小写字母映射为26进制数:0~25int hash(char lowercase){ return lowercase - 'a';}char firstUniqChar.原创 2021-08-29 19:31:32 · 89 阅读 · 0 评论 -
剑指 Offer II 072. 求平方根(牛顿迭代法)
解法:牛顿迭代法先上公式。对于x2=nx^2=nx2=n迭代公式为:xk+1=xk+nxk2x_{k+1}=\frac{x_k+\frac{n}{x_k}}{2}xk+1=2xk+xkn推导过程见数值分析、计算方法等相关书籍。int mySqrt(int n){ if(0 == n) return 0; double x0 = 2; double eps = 0.1; double x1; for(;;) { x1 = .原创 2021-08-29 17:12:04 · 206 阅读 · 0 评论 -
剑指 Offer 27. 二叉树的镜像
解法:先序遍历/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */struct TreeNode* mirrorTree(struct TreeNode* root){ if(root) { struct TreeNode *t原创 2021-08-29 16:21:00 · 65 阅读 · 0 评论 -
剑指 Offer 22. 链表中倒数第k个节点
方法一:栈一看到“倒”字,我就想到了栈。先遍历链表,将节点依次压栈,再弹出k−1k-1k−1个节点,栈顶就是倒数第kkk个节点了。/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */class Solution {public:原创 2021-08-29 15:39:24 · 83 阅读 · 0 评论 -
剑指 Offer 10- I. 斐波那契数列
传统办法是递归计算,但是当n比较大时,会收到递归深度的限制。同时,可以发现,在递归中存在重复计算问题。改进:(1)通过记忆前两个状态,避免重复计算,(2)改递归为迭代int fib(int n){ if(n==0 || n==1) return n; // 从f(2)开始迭代算到f(n) int f0 = 0; int f1 = 1; for(int i=2; i<=n; i++) { f1 = f0 + f1; .原创 2021-08-29 15:22:37 · 73 阅读 · 0 评论 -
剑指 Offer 57. 和为s的两个数字(二分查找、双指针)
解法一:二分查找对一个有序的递增数组进行查找,可以使用二分查找。/** * Note: The returned array must be malloced, assume caller calls free(). */ int binarySearch(int *nums, int left, int right, int x) { while(left <= right) { int mid = left + (right-left)/2; .原创 2021-08-27 13:53:28 · 110 阅读 · 0 评论 -
剑指 Offer 30. 包含min函数的栈(两个栈)
标准栈的push、pop时间复杂度都是O(1)O(1)O(1)。而min需要遍历栈才能得到,时间复杂度为O(n)O(n)O(n)。所以该题的难点在于如何使min的复杂度变为O(1)O(1)O(1)。如果使用一个min属性来保存最小值,那么在push时可以做到O(1)O(1)O(1)时间更新该属性,但是pop时却无法在O(1)O(1)O(1)时间得到前一个状态的最小值。看了评论区才恍然大悟,使用一个辅助栈来维护最小值。解法:辅助栈使用数据栈保存所有数据,使用辅助栈保存当前状态以及历史状态的最小值。原创 2021-08-26 19:49:35 · 107 阅读 · 0 评论