文章目录
Leetcode 14.最长公共前缀
C语言题解与思路
char* longestCommonPrefix(char** strs, int strsSize) {
int i,j,f,c=0;
for(i=0;i<strlen(strs[0]);i++)
{
f=1;
for(j=1;j<strsSize;j++)
{
if(strs[j][i]!=strs[j-1][i])
{
f=0;
break;
}
}
if(f==1)
{
c++;
}
else{
break;
}
}
if(c==0) return "";
char *a=(char*)malloc((c+1)*sizeof(char));
for(i=0;i<c;i++)
{
a[i]=strs[0][i];
}
a[c]='\0';
return a;
}
解题思路:首先从第一行的字符串开始循环,再通过数组下标竖向循环对比每一行同一个位置的字符是否相同,如果不相同,将f赋值为1作为标记,退出竖向对比的循环,通过f的值判断以i为下标的字符是否在整个竖向都相同,以此决定是否结束循环。
Leetcode 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
C语言题解与思路
/**
* 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().
*/
void swap(int *a, int *b)
{
int tem = *a;
*a = *b;
*b = tem;
}
int partSort(int *a, int left, int right)
{
int key = left;
while(left < right)
{
while(left < right && a[key] <= a[right])
{
right--;
}
while(left < right && a[key] >= a[left])
{
left++;
}
swap(&a[left], &a[right]);
}
swap(&a[left], &a[key]);
return left;
}
void QuickSort(int *a, int left, int right)
{
if(left >= right)
{
return;
}
int key = partSort(a, left, right);
QuickSort(a, left, key - 1);
QuickSort(a, key + 1, right);
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
int i, j, k, n = 20000;
int **str = (int **)malloc(sizeof(int *) * n);
*returnColumnSizes = (int *)malloc(sizeof(int) * n);
*returnSize = 0;
QuickSort(nums, 0, numsSize - 1);
for(i = 0; i < numsSize - 2; i++)
{
if(i > 0 && nums[i] == nums[i-1])
{
continue;
}
j = i + 1;
k = numsSize - 1;
while(j < k)
{
int sum = nums[i] + nums[j] + nums[k];
if(sum == 0)
{
str[*returnSize] = (int *)malloc(sizeof(int) * 3);
(*returnColumnSizes)[*returnSize] = 3;
str[*returnSize] = malloc(sizeof(int) * 3);
str[*returnSize][0] = nums[i];
str[*returnSize][1] = nums[j];
str[*returnSize][2] = nums[k];
(*returnSize)++;
int num1 = nums[j], num2 = nums[k];
while(nums[j] == num1 && j < k)
{
j++;
}
while(nums[k] == num2 && j < k)
{
k--;
}
}
else if(sum < 0){
j++;
}
else{
k--;
}
}
}
return str;
}
解题思路:
用快速排序将数组排序,运用双指针遍历数组。
不允许出现相同的输出,所以需要查重。
因为有三个数,第一个数用 for 循环遍历数组来确定,第二、三个数通过双指针来确定。
用快速排序使数组变为升序。
循环开头查重 i ,如果 i 大于 0 并且与前一个的值相等,跳过此次循环。
判断三数之和:
如果三个数的和等于 0 ,将三个数存入数组 str 中,指针 returnSize 加 1 ,然后对 j 和 k 进行查重。
如果三个数的和小于 0 ,j 加 1 。
如果三个数的和大于 0 ,k 减 1。
因为要求三个数的和,所以 i 只用循环 numsSize - 3 次。
最后返回二维数组 str 。
Leetcode 20.有效的括号
题目描述
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = “()”
输出:true
示例 2:
输入:s = “()[]{}”
输出:true
示例 3:
输入:s = “(]”
输出:false
提示:
- 1 <= s.length <= 104
- s 仅由括号 ‘()[]{}’ 组成
C语言的题解与思路
char pairs(char t)
{
if(t == ')')
{
return '(';
}
if(t == '}')
{
return '{';
}
if(t == ']')
{
return '[';
}
return 0;
}
bool isValid(char* s) {
int n = strlen(s);
if(n % 2 == 1)
{
return false;
}
int top = 0, str[n + 1];
for(int i = 0; i < n; i++)
{
char flag = pairs(s[i]);
if(flag != 0)
{
if(top == 0 || str[top - 1] != flag)
{
return false;
}
top--;
}
else
{
str[top++] = s[i];
}
}
return top == 0;
}
解题思路:
通过 [栈] 这一数据结构实现。
建立一个不小于原数组的数组 str ,用来存放遇到的左括号,通过变量 top 实现该数组的输入。
定义一个函数 pair ,将右括号转换为左括号,将左括号转换为 0 ,返回值存入变量 flag 中。
判断变量 flag ,如果时左括号,存入 str 数组中,top指向最新存入的左括号的下一个位置;如果是右括号,判断 top 是否为 0 或与最新的左括号是否不为同一类型,如果是,直接返回 false ,如果不是,说明左右括号的类型相同,通过 top 回退来将最新的左括号剔除。
最后确认 top 是否为 0 ,如果否,说明还有左括号没有消完,返回 false ;如果是,说明左右括号正好消完,返回 true 。
Leetcode 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 均按 非递减顺序 排列
C语言题解与思路
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
struct ListNode* head3=(struct ListNode*)malloc(sizeof(struct ListNode));
head3->next=NULL;
struct ListNode* p=head3;
while(list1&&list2)
{
if(list1->val<list2->val)
{
p->next=list1;
p=p->next;
list1=list1->next;
}
else{
p->next=list2;
p=p->next;
list2=list2->next;
}
}
if(list1)
{
p->next=list1;
}
if(list2)
{
p->next=list2;
}
return head3->next;
}
解题思路:
我的解法是先创建一个头指针head3并初始化,这个头指针是要在最后返回的,然后创建一个指针p指向头指针,用tem去合并传入函数的list1和list2成为head3。将list1和list2都不为空作为循环条件,在循环里不断比较指针里的val,val小的指针结点连接上p,然后该指针跳转到下一个结点。当有一个链表完全合并至新链表中后,判断哪个链表还有剩余数据,直接链接到新链表的最后。最后返回的是head->next,因为我是让指针从头节点下一位开始链接的。
解法优化:递归写法。
if (!l1)
return l2;
if (!l2)
return l1;
if (l1->val < l2->val){
l1->next = mergeTwoLists(l1->next, l2);
return l1;
}
else{
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
这是通过不断调用函数本身来合并链表,没有再创建一个新链表,哪个链表的第一个数据最小,最后就返回哪一个函数的头指针。
Leetcode 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
C语言题解和思路
int cmp(const void *a, const void *b)
{
int x = *(int *)a, y = *(int *)b;
return x - y;
}
bool containsDuplicate(int* nums, int numsSize) {
qsort(nums, numsSize, sizeof(int), cmp);
for(int i = 1; i < numsSize; i++)
{
if(nums[i] == nums[i - 1])
{
return true;
}
}
return false;
}
解题思路:
快排解题,最好用 qsort 函数实现快排,自己写快排容易超时。
先用 sqort 函数实现数组元素的排序,这时拥有相同值的元素就会挨在一起,再用 for循环遍历数组,不断比较相邻的元素是否相等,如果相等,返回 true ;如果循环结束时还没返回值,说明数组内没有重复元素,返回 false 。
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 仅由小写英文字母组成
C语言题解和思路
/**
* 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().
*/
void dfs(char *s, int n, int i, int **f, char ***ret, int *retSize, int *retColSize, char **ans, int *ansSize)
{
if(i == n)
{
char **tmp = malloc(sizeof(char *) * (*ansSize));
for(int j = 0; j < (*ansSize); j++)
{
int ansColSize = strlen(ans[j]);
tmp[j] = malloc(sizeof(char) * (ansColSize + 1));
strcpy(tmp[j], ans[j]);
}
ret[*retSize] = tmp;
retColSize[(*retSize)++] = *ansSize;
return;
}
for(int j = i; j < n; j++)
{
if(f[i][j] != 0)
{
char *sub = malloc(sizeof(char) * (j - i + 2));
for(int k = i; k <= j; k++)
{
sub[k - i] = s[k];
}
sub[j - i + 1] = '\0';
ans[(*ansSize)++] = sub;
dfs(s, n, j + 1, f, ret, retSize, retColSize, ans, ansSize);
(*ansSize)--;
}
}
}
char*** partition(char* s, int* returnSize, int** returnColumnSizes){
int n = strlen(s);
int maxlen = n * 2^(n);
char ***ret = malloc(sizeof(char **) * maxlen);
*returnSize = 0;
*returnColumnSizes = malloc(sizeof(int) * maxlen);
int *f[n];
for(int i = 0; i < n; i++)
{
f[i] = malloc(sizeof(int) * n);
for(int j = 0; j < n; j++)
{
f[i][j] = 1;
}
}
for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
f[i][j] = (s[i] == s[j]) && f[i + 1][j - 1];
}
}
char *ans[n];
int ansSize = 0;
dfs(s, n, 0, f, ret, returnSize, *returnColumnSizes, ans, &ansSize);
return ret;
}
解题思路:
深度搜索
首先为建立返回的三维数组 ret 并申请足够的空间,再建立二维数组 f ,f 用来判断字符下标 i 和 j 直接的子字符串是否是回文字符串,先初始化为 1 ,再通过遍历数组记录回文字符串。
将输入的字符串 s ,字符串 s 的长度 n ,递归处理的起始索引,保存是否为回文子串信息的二维数组 f ,保存所有回文子串分割结果的三维数组 ret ,返回的回文子串分割数组的大小的指针 retSize ,每个回文子串分割数组的大小的指针 retColSize ,保存当前回文子串分割的一个可能结果二维数组 ans ,保存 当前回文子串分割的长度的指针 ansSize 。
dfs函数开始时判断当前递归处理的起始索引是否等于当前字符串长度,当二者相等时,表示已经处理完整个字符串,即得到了一个可能的回文子串分割方案。然后将这个结果保存给 ret ,分割方案长度保存在 retColSize ,更新 retSize 并返回上一层递归。
当二者不相等时,在每个位置 i ,尝试将剩余的子串分割成回文子串。通过二维数组 f ,我们从 i 到字符串末尾的每个位置 j 开始,检查是否存在以 i 和 j 为边界的回文子串。
如果存在以 i 和 j 为边界的回文子串,则将该子串拷贝到临时数组ans中,并递归处理剩余子串。处理完后回退到上一个状态以继续尝试其他方案。