一些LeetCode的秒杀题,熟悉一下工程风格的代码补全。
目录:
(1) LeetCode26.删除有序数组中的重复项
(2) LeetCode136.只出现一次的数字
(3) LeetCode217.存在重复元素
(4) LeetCode242.有效的字母异位词
(5) LeetCode258.各位相加
(6) LeetCode268.丢失的数字
(7) LeetCode283.移动零
(8) LeetCode344.反转字符串
(9) LeetCode414.第三大的数
(10) LeetCode485.连续的1的个数
(11) LeetCode674.最长连续递增序列
(12) LeetCode709.转换成小写字母
(13) LeetCode747.至少是其他数字两倍的最大数
(14) LeetCode771.宝石与石头
(15) LeetCode852.山脉数组的峰顶索引
(16) LeetCode896.单调数列
(17) LeetCode1295. 统计位数为偶数的数字
(18) LeetCode1464. 数组中两元素的最大乘积
(19) LeetCode1848. 到目标元素的最小距离
(20) LeetCode1952.三除数
(1)26. 删除有序数组中的重复项
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
提示:
0 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums
已按升序排列
思路:
本题考察双指针。i负责遍历数组nums,j负责用不相同的元素去覆盖原来的。
代码:

int removeDuplicates(int* nums, int numsSize){ if(numsSize<2) return numsSize; int i,j=0; for(i=1;i<numsSize;i++) if(nums[j]!=nums[i]) nums[++j]=nums[i]; return ++j; }
执行结果:
(2)136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
思路:
众所周知,a xor a = 0。所以将数组中的所有数字异或一遍,重复出现过的数字会被消去,最后剩下的那个就是答案。
(同题:2021 GXCPC 热身赛B题,当时用set写的。很显然异或的效率更高)
代码:

int singleNumber(int* nums, int numsSize){ int i,ans=nums[0]; for(i=1;i<numsSize;i++) ans^=nums[i]; return ans; }
执行结果:
(3)217. 存在重复元素
给定一个整数数组,判断是否存在重复元素。
如果存在一值在数组中出现至少两次,函数返回 true
。如果数组中每个元素都不相同,则返回 false
。
C++ part
思路:
用set判重,一行秒了。
代码:

class Solution { public: bool containsDuplicate(vector<int>& nums) { return set<int>(nums.begin(),nums.end()).size()!=nums.size(); } };
执行结果:
C part
思路:对数组进行排序,然后遍历数组查找重复的。
代码:

int cmp(const void* a, const void* b){ return (*(int*)a)-(*(int*)b); } bool containsDuplicate(int* nums, int numsSize) { int i; qsort(nums,numsSize,sizeof(int),cmp); for(i=1;i<numsSize;i++) if(nums[i]==nums[i-1]) return 1; return 0; }
执行结果:
(4)242. 有效的字母异位词
给定两个字符串 s
和 t
,编写一个函数来判断 t
是否是 s
的字母异位词。
注意:若 s
和 t
中每个字符出现的次数都相同,则称 s
和 t
互为字母异位词。
思路:这里涉及到一个点,灵活理解字符和数字之间的对应关系(ACSII表),每一个字符都会对应一个数字。比如字符‘a’代表的数字就是97。'a'-'a'的运算结果就是97-97=0。所以可以把26个字母理解为0-25的数字。遍历数组s和t,用两个大小为26的int型数组统计每个字母出现的次数,然后遍历统计数组去比较即可。运气好预编译0ms搞了一波100%
代码:

bool isAnagram(char * s, char * t){ int i,n,num_s[26]={0},num_t[26]={0}; n=strlen(s); for(i=0;i<n;i++) num_s[s[i]-'a']++; n=strlen(t); for(i=0;i<n;i++) num_t[t[i]-'a']++; for(int i=0;i<26;i++) if(num_s[i]!=num_t[i]) return 0; return 1; }
执行结果:
(5)258. 各位相加
给定一个非负整数 num
,反复将各个位上的数字相加,直到结果为一位数。
思路:
数论小题或者小题都不算。%9就行了,很容易推。。。
代码:

int addDigits(int num){ return (num-1)%9+1; }
执行结果:
(6)268. 丢失的数字
给定一个包含 [0, n]
中 n
个数的数组 nums
,找出 [0, n]
这个范围内没有出现在数组中的那个数。
思路:
对数组排序,可以找到丢失的数字。
对数组求和,通过等差数列公式计算也可以得到丢失的数字。
代码:

int cmp(const void* a, const void* b){ return (*(int*)a)-(*(int*)b); } int missingNumber(int* nums, int numsSize){ qsort(nums,numsSize,sizeof(int),cmp); int i; for(i=0;i<numsSize;i++) if(nums[i]!=i) return i; return numsSize; }

int missingNumber(int* nums, int numsSize){ int i,sum=0; for(i=0;i<numsSize;i++) sum+=nums[i]; return (1+numsSize)*(numsSize)/2-sum; }
执行结果:
(7)283. 移动零
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入:[0,1,0,3,12]
输出:[1,3,12,0,0]
说明:
- 必须在原数组上操作,不能拷贝额外的数组。
- 尽量减少操作次数。
思路:
参考作业第1题,双指针把非0元素移动到前面。然后把剩下来的所有格子全都赋0即可。

void moveZeroes(int* nums, int numsSize){ int i,j=0; for(i=0;i<numsSize;i++) if(nums[i]) nums[j++]=nums[i]; for(;j<numsSize;j++) nums[j]=0; }
执行结果:
(8)344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[]
的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
思路:
遍历,交换第i和第n-i个元素即可。
代码:

void reverseString(char* s, int sSize){ int i,tmp; for(i=0;i<sSize/2;i++) { tmp=s[i]; s[i]=s[sSize-1-i]; s[sSize-1-i]=tmp; } }
执行结果:
(9)414. 第三大的数
给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。
思路:用m1,m2,m3存第1,2,3大的数。对于数据[1,1,2]输出应该为最大的数2。另外有个1,2,-2147483648的数据要单独留意一下。大型三目运算符场,三目运算符真的比调用if...else...或者max(a,b)快。ACMer日常抠时间(
代码:

#define INF -2147483648 int thirdMax(int* nums, int numsSize) { int m1,m2,m3,i=0,t1=0,t2=0,t3=0; m1=m2=m3=INF; if(numsSize==1) return nums[0]; if(numsSize==2) return nums[0]>nums[1]?nums[0]:nums[1]; for(i=0;i<numsSize;i++) { m1=nums[i]>m1?(t1++,m3=m2,m2=m1,nums[i]):m1; m2=nums[i]>m2?(nums[i]<m1?(t2++,m3=m2,nums[i]):m2):m2; m3=nums[i]>m3?(nums[i]<m2?(t3++,nums[i]):m3):m3; if(nums[i]==m3) t3++; } if(m3<m2&&m2<m1&&(t1>=3||t2>=2||t3>=1)) return m3; return m1; }
执行结果:
(10)485. 最大连续 1 的个数
给定一个二进制数组, 计算其中最大连续 1 的个数。
思路:遍历一遍数组,碰到1的时候cnt++,碰到0的时候cnt=0。然后对比较n遍ans得到结果。
代码:

int findMaxConsecutiveOnes(int* nums, int numsSize){ int i,cnt=0,ans=0; for(i=0;i<numsSize;i++) { cnt=nums[i]>0?cnt+1:0; ans=ans>cnt?ans:cnt; } return ans; }
执行结果:
(11)674. 最长连续递增序列
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l
和 r
(l < r
)确定,如果对于每个 l <= i < r
,都有 nums[i] < nums[i + 1]
,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]]
就是连续递增子序列。
提示:
1 <= nums.length <= 10^4
-10^9 <= nums[i] <= 10^9
思路:这题要求最长的连续上升子序列,当遇到不上升的项的时候从头计数即可。维护一个max值。
拓展:LIS,最长上升子序列(不连续),是很经典很重要的一个dp题。可以看看这篇博客
代码:

int findLengthOfLCIS(int* nums, int numsSize){ if(numsSize==1) return 1; int i,mx=1,cnt=1; for(i=1;i<numsSize;i++) { cnt=nums[i]>nums[i-1]?cnt+1:1; mx=cnt>mx?cnt:mx; } return mx; }
执行结果:
(12)709. 转换成小写字母
给你一个字符串 s
,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。
思路:
char与数字的灵活转化。当字符在'A'~'Z'中时,加上k='a'-'A',就可以将大写字母换成小写了。
代码:

char * toLowerCase(char * s){ int n=strlen(s),k='a'-'A',i; for(int i=0;i<n;i++) if('A'<=s[i]&&s[i]<='Z') s[i]+=k; return s; }
执行结果:
(13)747. 至少是其他数字两倍的最大数
给你一个整数数组 nums
,其中总是存在 唯一的 一个最大整数 。
请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回 最大元素的下标 ,否则返回 -1
。
思路:
遍历两遍,找到最大的数,最大数的下标,第二大的数。若最大的数字≥第二大的数2倍,则满足题意输出下标。否则输出-1。
代码:

int dominantIndex(int* nums, int numsSize){ if(numsSize==1) return 0; int i,n,m,k; n=m=-1; for(i=0;i<numsSize;i++) if(nums[i]>n) { k=i; n=nums[i]; } for(i=0;i<numsSize;i++) if(nums[i]>m&&nums[i]!=n) m=nums[i]; return n>=m*2?k:-1; }
执行结果:
(14)771. 宝石与石头
给定字符串J
代表石头中宝石的类型,和字符串 S
代表你拥有的石头。 S
中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。
J
中的字母不重复,J
和 S
中的所有字符都是字母。字母区分大小写,因此"a"
和"A"
是不同类型的石头。
思路:
打表,标记J中所有出现过的字母。遍历S,对于S中每个元素去查表,如果是宝石则cnt++。
代码:

int numJewelsInStones(char * jewels, char * stones){ int i,cnt=0,a[200]={0},n=strlen(jewels); for(i=0;i<n;i++) a[jewels[i]]=1; n=strlen(stones); for(i=0;i<n;i++) if(a[stones[i]]) cnt++; return cnt; }
执行结果:
(15)852. 山脉数组的峰顶索引
arr
称为 山脉数组 :
arr.length >= 3
- 存在
i
(0 < i < arr.length - 1
)使得:arr[0] < arr[1] < ... arr[i-1] < arr[i]
arr[i] > arr[i+1] > ... > arr[arr.length - 1]
给你由整数组成的山脉数组 arr
,返回任何满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
的下标 i
。
提示:
3 <= arr.length <= 104
0 <= arr[i] <= 106
- 题目数据保证
arr
是一个山脉数组
思路:找到第一个开始下降的位置,输出。
代码:

int peakIndexInMountainArray(int* arr, int arrSize) { int i; for(i=1;i<arrSize;i++) if(arr[i]<arr[i-1]) return i-1; return 0; }
执行结果:
(16)896. 单调数列
如果数组是单调递增或单调递减的,那么它是单调的。
如果对于所有 i <= j
,A[i] <= A[j]
,那么数组 A
是单调递增的。 如果对于所有 i <= j
,A[i]> = A[j]
,那么数组 A
是单调递减的。
当给定的数组 A
是单调数组时返回 true
,否则返回 false
。
思路:
如果A[i] < A[j],满足递增,则标记a=1。若递减则标记b=1。相等的时候不记标记。若a=b=1是不是单调数组,其余情况都是。
代码:

bool isMonotonic(int* nums, int numsSize) { int i,a=0,b=0; for(i=1;i<numsSize;i++) { if(nums[i]<nums[i-1]) a=1; if(nums[i]>nums[i-1]) b=1; } if(a+b==2) return 0; return 1; }
执行结果:
(17)1295. 统计位数为偶数的数字
给你一个整数数组 nums
,请你返回其中位数为 偶数 的数字的个数。
思路:
判断一个数字位数的方法,让n不断去除10,每除一次位数+1,一直到n=0为止。注意,本题数据规模保证n>0,如果扩大数据规模,n=0是不进循环的,所以要特殊判断一下。
代码:

int check(int n) { int u=0; while(n) { n/=10; u++; } if(u%2) return 0; return 1; } int findNumbers(int* nums, int numsSize) { int i,cnt=0; for(i=0;i<numsSize;i++) cnt+=check(nums[i]); return cnt; }
执行结果:
(18)1464. 数组中两元素的最大乘积
给你一个整数数组 nums
,请你选择数组的两个不同下标 i
和 j
,使 (nums[i]-1)*(nums[j]-1)
取得最大值。
请你计算并返回该式的最大值。
思路:
找到数组中不重复的两个最大值。可以值重复,但是位置不重复。排序取最后两个即可。懒得写排序所以遍历了两遍。
代码:

int maxProduct(int* nums, int numsSize) { int i,j,max1=-1,max2=-1; for(i=0;i<numsSize;i++) if(nums[i]>max1) { j=i; max1=nums[i]; } for(i=0;i<numsSize;i++) if(nums[i]>max2&&i!=j) max2=nums[i]; return (max1-1)*(max2-1); }
执行结果:
(19)1848. 到目标元素的最小距离
给你一个整数数组 nums
(下标 从 0 开始 计数)以及两个整数 target
和 start
,请你找出一个下标 i
,满足 nums[i] == target
且 abs(i - start)
最小化 。注意:abs(x)
表示 x
的绝对值。
返回 abs(i - start)
。
题目数据保证 target
存在于 nums
中。
思路:没法直接用abs函数需要手写一个。遍历nums数组中的每一个元素,对于满足 nums[i] == target
的元素去判断abs(i - start)
,维护最小值即可。
代码:

int as(int n) { return n<0?-1*n:n; } int getMinDistance(int* nums, int numsSize, int target, int start) { int i,ans=numsSize; for(i=0;i<numsSize;i++) { if(nums[i]==target) ans=ans<as(i-start)?ans:as(i-start); } return ans; }
执行结果:
(20)1952. 三除数
给你一个整数 n
。如果 n
恰好有三个正除数 ,返回 true
;否则,返回 false
。
如果存在整数 k
,满足 n = k * m
,那么整数 m
就是 n
的一个 除数 。
思路:数据规模很小只有1e4,直接暴力去算就可以了。遍历每一个比n小的数,去判断是不是n的因子。
代码:

bool isThree(int n) { int i,cnt=0; for(i=1;i<=n;i++) if(n%i==0) cnt++; return cnt==3; }
执行结果: