23大一下Web三面题解
20.有效的括号
给定一个只包括
'('
,')'
,'{'
,'}'
,'['
,']'
的字符串s
,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = "()" 输出:true
示例 2:
输入:s = "()[]{}" 输出:true
示例 3:
输入:s = "(]" 输出:false
提示:
1 <= s.length <= 104
s
仅由括号'()[]{}'
组成bool isValid(char* s) { int l = strlen(s); int p=0,i=0; char arr[l]; //栈数组 for(i=0;i<l;i++){ if(s[i]=='('||s[i]=='['||s[i]=='{'){ //若是左括号就入栈 arr[p++]=s[i]; }else{ //右括号的情况 if(p<=0){ //栈空,自然无法配对,直接返回false return false; } if(s[i]==')'){ if(arr[p-1]!='('){ //不匹配,返回假 return false; }else{ p--; //匹配,将栈指针减一实现出栈 } }else if(s[i]==']'){ if(arr[p-1]!='['){ return false; }else{ p--; } }else{ if(arr[p-1]!='{'){ return false; }else{ p--; } } } } if(p>0){ return false; //匹配到最后栈一定为空,否则就为假 } return true; }
2810.故障键盘
你的笔记本键盘存在故障,每当你在上面输入字符
'i'
时,它会反转你所写的字符串。而输入其他字符则可以正常工作。给你一个下标从 0 开始的字符串
s
,请你用故障键盘依次输入每个字符。返回最终笔记本屏幕上输出的字符串。
示例 1:
输入:s = "string" 输出:"rtsng" 解释: 输入第 1 个字符后,屏幕上的文本是:"s" 。 输入第 2 个字符后,屏幕上的文本是:"st" 。 输入第 3 个字符后,屏幕上的文本是:"str" 。 因为第 4 个字符是 'i' ,屏幕上的文本被反转,变成 "rts" 。 输入第 5 个字符后,屏幕上的文本是:"rtsn" 。 输入第 6 个字符后,屏幕上的文本是: "rtsng" 。 因此,返回 "rtsng" 。
示例 2:
输入:s = "poiinter" 输出:"ponter" 解释: 输入第 1 个字符后,屏幕上的文本是:"p" 。 输入第 2 个字符后,屏幕上的文本是:"po" 。 因为第 3 个字符是 'i' ,屏幕上的文本被反转,变成 "op" 。 因为第 4 个字符是 'i' ,屏幕上的文本被反转,变成 "po" 。 输入第 5 个字符后,屏幕上的文本是:"pon" 。 输入第 6 个字符后,屏幕上的文本是:"pont" 。 输入第 7 个字符后,屏幕上的文本是:"ponte" 。 输入第 8 个字符后,屏幕上的文本是:"ponter" 。 因此,返回 "ponter" 。
提示:
1 <= s.length <= 100
s
由小写英文字母组成
s[0] != 'i'
void reverse(char* s,int i,int j){ //反转函数 while(i<j){ char temp=s[i]; s[i++]=s[j]; s[j--]=temp; } } char* finalString(char* s) { int i=0; int l=strlen(s); for(i=0;i<l;i++){ //正常遍历,遇到i就将前面的字符反转 if(s[i]=='i'){ reverse(s,0,i-1); } } int j=0; for(i=0;i<l;i++){ //再遍历一次,将字符串里面的i去掉 if(s[i]!='i'){ s[j++]=s[i]; } } s[j]='\0'; return s; }
15.三数之和
给你一个整数数组
nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j
、i != k
且j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为
0
且不重复的三元组。**注意:**答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
提示:
3 <= nums.length <= 3000
-105 <= nums[i] <= 105
/** * Return an array of arrays of size *returnSize. * The sizes of the arrays are returned as *returnColumnSizes array. * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). */ /*要在数组里面找出相加等于零的三元组,可以先将数组排个序,相加时的数值大小就会变得可以控制,这样便于找出答案*/ int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) { int i,j; int **ans=(int**)malloc(sizeof(int*)*18000); int anstop=0; for(i=0;i<numsSize-1;i++){ //冒泡排序,将数组从小到大来排列 for(j=0;j<numsSize-i-1;j++){ if(nums[j]>nums[j+1]){ int temp =nums[j]; nums[j]=nums[j+1]; nums[j+1]=temp; } } } for(i=0;i<numsSize-2;i++){ if(nums[i]>0){ //如果第一个数就大于零了,就没必要继续进行比较了,直接返回答案 break; } if(i>0&&nums[i]==nums[i-1]){ //这一段代码的作用是去重,这里和前一个数比较是为了去重的同时不漏掉答案 continue; } int left=i+1; int right=numsSize-1; //在剩下的数的两端,往里面收,寻找合适的三元组 while(left<right){ int sum=nums[i]+nums[left]+nums[right]; if(sum>0){ //若是大于零,则要将三元组的值减小,就是将right往左移动 right--; }else if(sum<0){ //小于零则left往右移动 left++; }else{ int *arr=(int*)malloc(sizeof(int)*3); //找到了合适的三元组,分配内存,再存入二维数组里面 arr[0]=nums[i]; arr[1]=nums[left]; arr[2]=nums[right]; ans[anstop++]=arr; while(right>left&&nums[right]==nums[right-1]){ //去重 right--; } while(left<right&&nums[left]==nums[left+1]){ left++; } left++; right--; } } } *returnSize=anstop; *returnColumnSizes=(int*)malloc(sizeof(int)*anstop); int z; for(z=0;z<anstop;z++){ (*returnColumnSizes)[z]=3; //设置返回数组的列数 } return ans; }
21.合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
提示:
两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
l1
和l2
均按 非递减顺序 排列struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { struct ListNode* newhead = (struct ListNode*)malloc(sizeof(struct ListNode)); newhead->next = NULL; struct ListNode* cur = newhead; while(list1 != NULL || list2 != NULL){ if(list1 == NULL){ cur->next = list2; break; } if(list2 == NULL){ cur->next = list1; break; } if(list1->val < list2->val){ cur->next = list1; list1 = list1->next; }else{ cur->next = list2; list2 = list2->next; } cur = cur->next; } return newhead->next; }
179.最大数
给定一组非负整数
nums
,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。**注意:**输出结果可能非常大,所以你需要返回一个字符串而不是整数。
示例 1:
输入:nums = [10,2] 输出:"210"
示例 2:
输入:nums = [3,30,34,5,9] 输出:"9534330"
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 109
//本题的关键就是开始的排序,从结果出发的话,数组里面每个数的位置都是固定的,这样才有了组合起来的最大值,通过冒泡排序,可以比较两个数的两种组合实现值的大小,不断把组合起来数值小的那个数往后排,这些往后移动的数都是在每一次循环中最适合放在末位的数,最后得到的排序就是题目要求的排序。 void sort(int* num,int numsSize){ for(int i=0;i<numsSize-1;i++){ for(int j=0;j<numsSize-i-1;j++){ char s1[100000]; char s2[100000]; sprintf(s1,"%d%d",num[j],num[j+1]); sprintf(s2,"%d%d",num[j+1],num[j]); if(strcmp(s2,s1)>0){ int temp=num[j]; num[j]=num[j+1]; num[j+1]=temp; } } } } char *largestNumber(int* nums, int numsSize){ sort(nums,numsSize); if(nums[0]==0){ //如果第一个数为0的话,意味着后面的数都是0 return "0"; } char* ans=(char*)malloc(sizeof(char)*10000000); //为答案数组分配内存 memset(ans,'\0',10000000); //因为一开始分配了很多内存,然后答案也是作为字符返回,答案的长度不太好确定,就全部设置为'\0' for(int i=0;i<numsSize;i++){ //这里是将排好序的数拼接起来 char s1[10000]; sprintf(s1,"%d",nums[i]); strcat(ans,s1); } return ans; }
LCR 086. 分割回文串
给定一个字符串
s
,请将s
分割成一些子串,使每个子串都是 回文串 ,返回 s 所有可能的分割方案。回文串 是正着读和反着读都一样的字符串。
示例 1:
输入:s = "google" 输出:[["g","o","o","g","l","e"],["g","oo","g","l","e"],["goog","l","e"]]
示例 2:
输入:s = "aab" 输出:[["a","a","b"],["aa","b"]]
示例 3:
输入:s = "a" 输出:[["a"]]
提示:
1 <= s.length <= 16
s
仅由小写英文字母组成对于这道题目,关键点是处理好分割点,然后和答案数组的处理,因为题目要求的是将字串分割成每一个都是回文串
char** path; int pathtop; char*** ans; int anstop; int* anssize; void copy() { //避免函数复杂,这里单独写一个函数将path数组里面记录的组合放入安安数组 char** temp = (char**)malloc(sizeof(char*) * pathtop); int i = 0; for(i = 0; i < pathtop; i++) { temp[i] = path[i]; } ans[anstop] = temp; anssize[anstop++] = pathtop; } char* cutstring(char* str,int startindex, int endindex) { //这是将原数组分割,将分割后的字符串拿出来 char* temp = (char*)malloc(sizeof(char) * (endindex - startindex + 2)); int i; int index = 0; for(i = startindex; i <= endindex; i++) { temp[index++] = str[i]; } temp[index] = '\0'; return temp; } bool ishui(char* str, int startindex, int endindex) { //判断是否时回文串 while(startindex <= endindex) { if(str[startindex++] != str[endindex--]) { return 0; } } return 1; } void backtracking(char* str,int strlen, int startindex) { if(startindex >= strlen) { //递归结束条件,记录过的符合要求的子串放入答案数组里面 copy(); return; } int i; for(i = startindex; i < strlen; i++) { //从当前数组开始向后遍历 if(ishui(str, startindex, i)) { //如果当前字符串符合要求,则记录,然后进入下一层递归 path[pathtop++] = cutstring(str, startindex, i); }else { //要是不符合回文串,后面也就没必要遍历了 continue; } backtracking(str, strlen, i + 1); pathtop--; //回溯,将前一个记录的字符串弹出 } } char*** partition(char* s, int* returnSize, int** returnColumnSizes){ int l = strlen(s); path = (char**)malloc(sizeof(char*) * l); ans = (char***)malloc(sizeof(char**) * 40000); anssize = (int*)malloc(sizeof(int) * 40000); anstop = pathtop = 0; backtracking(s, l, 0); *returnSize = anstop; *returnColumnSizes = (int*)malloc(sizeof(int) * anstop); int i; for(i = 0; i < anstop; i++) { (*returnColumnSizes)[i] = anssize[i]; } return ans; }
217.存在重复元素
给你一个整数数组
nums
。如果任一值在数组中出现 至少两次 ,返回true
;如果数组中每个元素互不相同,返回false
。示例 1:
输入:nums = [1,2,3,1] 输出:true
示例 2:
输入:nums = [1,2,3,4] 输出:false
示例 3:
输入:nums = [1,1,1,3,3,4,3,2,4,2] 输出:true
提示:
1 <= nums.length <= 105
-109 <= nums[i] <= 109
//这道题目排序后再判断相邻的数是否重复,但是效率不高的排序会超时,这里用系统自己带的快排 int compare(const void *a, const void *b) { return (*(int*)a - *(int*)b); } bool containsDuplicate(int* nums, int numsSize) { qsort(nums,numsSize,sizeof(int),compare); for(int i=0;i<numsSize-1;i++){ if(nums[i]==nums[i+1]){ return true; } } return false; }
58. 最后一个单词的长度
给你一个字符串
s
,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。单词 是指仅由字母组成、不包含任何空格字符的最大
子字符串
示例 1:
输入:s = "Hello World" 输出:5 解释:最后一个单词是“World”,长度为5。
示例 2:
输入:s = " fly me to the moon " 输出:4 解释:最后一个单词是“moon”,长度为4。
示例 3:
输入:s = "luffy is still joyboy" 输出:6 解释:最后一个单词是长度为6的“joyboy”。
提示:
1 <= s.length <= 104
s
仅有英文字母和空格' '
组成s
中至少存在一个单词
//要计算最后一个单词长度,直接从字符串末尾开始往前数,再添加合适的判断就可求解
int lengthOfLastWord(char* s) {
int l=strlen(s);
int ans=0;
for(int i=l-1;i>=0;i--){ //有两种遇到空格的情况,一种是末尾有空格,另一种是结束时遇到的空格
if(s[i]==' '&&ans>0){ //这里是处理结束时的空格,如果已经遇到过单词,再遇到空格,则说明结束了
break;
}
if(s[i]!=' '){ //计算答案数
ans++;
}
//末尾空格不用多加处理
}
return ans;
}
出:4
解释:最后一个单词是“moon”,长度为4。
**示例 3:**
输入:s = “luffy is still joyboy”
输出:6
解释:最后一个单词是长度为6的“joyboy”。**提示:** - `1 <= s.length <= 104` - `s` 仅有英文字母和空格 `' '` 组成 - `s` 中至少存在一个单词
//要计算最后一个单词长度,直接从字符串末尾开始往前数,再添加合适的判断就可求解
int lengthOfLastWord(char* s) {
int l=strlen(s);
int ans=0;
for(int i=l-1;i>=0;i--){ //有两种遇到空格的情况,一种是末尾有空格,另一种是结束时遇到的空格
if(s[i]==' '&&ans>0){ //这里是处理结束时的空格,如果已经遇到过单词,再遇到空格,则说明结束了
break;
}
if(s[i]!=' '){ //计算答案数
ans++;
}
//末尾空格不用多加处理
}
return ans;
}