leetcode刷题



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中,并递归处理剩余子串。处理完后回退到上一个状态以继续尝试其他方案。


  • 25
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值