一些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; }
執行結果: