leetcode20:删除有效括号
题目
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
解题思路
1.求出字符串s的长度,定义一个顺序栈并初始化
2.从左往右扫描字符串s
当扫描到“左括号”(即'('、'['、'{'这三种),则将其入栈;
否则,当扫描到“右括号”且栈为空时,则括号匹配失败;
而当扫描到“右括号”且栈不为空时,出栈一个元素,并将其与该“右括号”进行匹配判断。
3.当扫描完整个字符串s时:
若栈不为空,则括号匹配失败;否则,括号匹配成功。
代码如下
bool isValid(char* s) {
int len = strlen(s);
char a[len];
int top = -1;
for (int i = 0; i < len; i++) {
if (s[i] == '(' || s[i] == '[' || s[i] == '{') {
a[++top] = s[i];
} else {
if (top == -1)
return false;
char b;
b = a[top--];
if (s[i] == ')' && b != '(')
return false;
if (s[i] == ']' && b != '[')
return false;
if (s[i] == '}' && b != '{')
return false;
}
}
if (top != -1)
return false;
return true;
}
leetcode14最长公共前缀
题目
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例
示例 1:
输入:strs = ["flower","flow","flight"] 输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"] 输出:"" 解释:输入不存在公共前缀。
解题思路
1.当数组长度为0时,返回空字符串
2.函数通过两层循环来遍历数组的每一个元素,外层循环遍历第一个字符串(strs[0])的每一个字符,内层循环则遍历剩余的所有字符串。在内层循环中,函数比较当前位置的字符是否在所有字符串中都相同。如果有任何一个字符串在当前位置的字符与第一个字符串不同,那么函数就将第一个字符串在当前位置的字符设为字符串结束符(\0),并返回第一个字符串。
3.如果两层循环都顺利结束,那么说明第一个字符串的所有字符都是所有字符串的公共前缀,函数直接返回第一个字符串。
代码实现
char* longestCommonPrefix(char** strs, int strsSize) {
if (strsSize == 0) {
return "";
}
for (int i = 0; i < strlen(strs[0]); i++) {
for (int j = 1; j < strsSize; j++) {
if (strs[0][i] != strs[j][i])
{
strs[0][i] = '\0';
return strs[0];
}
}
}
return strs[0];
}
leetcode2810:故障键盘
题目:
你的笔记本键盘存在故障,每当你在上面输入字符 '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" 。
解题思路:
当字符串进行反转后,在末尾添加字符等价于「不对字符串进行反转,并且在开头添加字符」。因此,我们可以使用一个双端队列和一个布尔变量 head 来维护答案:
当遇到非 “i” 的字符时,如果 head为真,就在队列的开头添加字符,否则在队列的末尾添加字符;
当遇到 “i”时,将 head 取反。
head\textit{head}head 的初始值为假。这样一来,每一个字符只需要 O(1)O(1)O(1) 的时间进行处理。
当处理完所有的字符后,如果 head 为真,那么将队列中的字符反序构造出答案字符串,否则正序构造出答案字符串。
代码实现
char* finalString(char* s) {
int len = strlen(s);
char q1[len], q2[len];
int pos1 = 0, pos2 = 0;
bool head = false;
for (int i = 0; i < len; i++) {
char ch = s[i];
if (ch != 'i') {
if (head) {
q1[pos1++] = ch;
} else {
q2[pos2++] = ch;
}
} else {
head = !head;
}
}
char *ans = (char *)malloc(sizeof(char) * (len + 1));
int pos = 0;
if (head) {
for (int i = pos2 - 1; i >= 0; i--) {
ans[pos++] = q2[i];
}
memcpy(ans + pos, q1, sizeof(char) * pos1);
} else {
for (int i = pos1 - 1; i >= 0; i--) {
ans[pos++] = q1[i];
}
memcpy(ans + pos, q2, sizeof(char) * pos2);
}
ans[pos1 + pos2] = '\0';
return ans;
}
leetcode21:合并两个有序链表
题目:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
示例:
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
代码实现
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//如果List1和list2中有一个为空就直接返回另一个链表
if(list1 == NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
}
//定义l1,l2指针分别指向list1和list2的头节点
ListNode* l1, *l2;
ListNode* newhead, *newtail;
//给新链表的开辟一个哨兵位
newhead = newtail = (ListNode*)malloc(sizeof(ListNode));
l1 = list1,l2 = list2;
while(l1 && l2)
{
if(l1->val <= l2->val)
{
newtail->next = l1;
newtail = newtail->next;
l1 = l1->next;
}
else
{
newtail->next = l2;
newtail = newtail->next;
l2 = l2->next;
}
}
if(l1)
{
newtail->next = l1;
}
if(l2)
{
newtail->next = l2;
}
//新链表的第一个节点是头节点为无效数据,因此返回头节点的next
return newhead->next;
}
leetcode15:两数之和
题目:
给你一个整数数组 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 。
解题思路:
三数之和是两数之和的困难版,但是两者的思路是大致相同的,两数之和我们采用的是双指针分别数组开始和末尾分别向中间走的来寻找。而三数之和,我们还是采用这种办法,不过我们需要对第三个数进行一些处理,大概的思路是先定好一个数,然后在剩下的数组找目标值,就变成了熟悉的两数之和。
代码实现:
int cmp(const void* pa, const void* pb){
int a=*(int*)pa;
int b=*(int*)pb;
return a>b?1:-1;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
int base=100;//数组的初始长度,可更改
//初始化处理返回值,二维数组的大小和保存每一个一维数组大小的数组的空间保持一致
int** res=(int**)malloc(sizeof(int*)*base);
*returnColumnSizes=(int*)malloc(sizeof(int)*base);
*returnSize=0;
int i,j,k;
//排序
qsort(nums,numsSize,sizeof(int),cmp);
for(i=0;i<numsSize;i++){
//先确定第三个数的值,再对剩下的两个数进行两数之和的操作
//若本次的第三个数与上一次的情况相同,则跳过这个数
if(i>0&&nums[i]==nums[i-1])
continue;
//给定nums[i],以j,k作为双指针进行两数之和操作
j=i+1;
k=numsSize-1;
while(j<k){
int sum=nums[i]+nums[j]+nums[k];
if(sum==0){//刚好遇见符合要求的三元组
//申请返回值二维数组的空间
res[*returnSize]=(int*)malloc(sizeof(int)*3);
//每一个数组大小都为3
(*returnColumnSizes)[*returnSize]=3;
//给申请的空间赋值
res[*returnSize][0]=nums[i];
res[*returnSize][1]=nums[j];
res[*returnSize][2]=nums[k];
//二维数组的行数加1
(*returnSize)++;
//如果二维数组的大小达到初始设定的行数,则进行空间扩容
if(*returnSize==base){
base*=2;
res=(int**)realloc(res,sizeof(int*)*base);
*returnColumnSizes=(int*)realloc(*returnColumnSizes,sizeof(int)*base);
}
//记录符合要求的两个数,进行去重
int num1=nums[j],num2=nums[k];
while(nums[j]==num1&&j<k)
j++;
while(nums[k]==num2&&j<k)
k--;
}
//若三个数之和小于0,则左边的指针右移
else if(sum<0)
j++;
//若三个数的之和大于0,则右边的指针往左移
else k--;
}
}
return res;
}