LeetCode刷题计划--C语言

编程基础0到1–简单题

题目一: 1768. 交替合并字符串

题解

char* mergeAlternately(char* word1, char* word2) {
   
    int len1 = strlen(word1);
    int len2 = strlen(word2);

    int len = len1 + len2;
    char* result = malloc(len * sizeof(char) + 1); // 申请字符串空间

    int i = 0;
    while (i < len1 && i < len2) {
   
        result[i * 2] = word1[i];
        result[i * 2 + 1] = word2[i];
        i = i + 1;
    }

    if (len1 > i) {
   
        for (int j = 0; j < len1 - i; j++) {
   
            result[i * 2 + j] = word1[i + j];
        }
    }

    if (len2 > i) {
   
        for (int j = 0; j < len2 - i; j++) {
   
            result[i * 2 + j] = word2[i + j];
        }
    }

    result[len] = '\0'; // 注意'\0'是占位置的,result字符串以'\0'结尾
    return result;
}

题目二: 389. 找不同

题解

  • 方法一:计数。首先遍历字符串 s,对其中的每个字符都将计数值加1;然后遍历字符串t,对其中的每个字符都将计数值减1。当发现某个字符计数值为负数时,说明该字符在字符串 t中出现的次数大于在字符串 s中出现的次数,因此该字符为被添加的字符。
  • 方法二:求和。 将字符串 s 中每个字符的 ASCII 码的值求和,得到 As,对字符串t同样的方法得At。两者的差值At−As​即代表了被添加的字符。
  • 方法三:位运算。如果将两个字符串拼接成一个字符串,则问题转换成求字符串中出现奇数次的字符。
char findTheDifference(char* s, char* t) {
   
    
    int len1 = strlen(s);
    int len2 = strlen(t);

    int As = 0;
    int At = 0;

    for (int i = 0; i < len1; i++) {
   
        As += s[i];
    }

    for (int i = 0; i < len2; i++) {
   
        At += t[i];
    }

    return At - As;
}

题目三: 28. 找出字符串中第一个匹配项的下标

题解

  • 方法一: 暴力匹配。 我们可以让字符串 needle 与字符串 haystack 的所有长度为 mmm 的子串均匹配一次。
    为了减少不必要的匹配,我们每次匹配失败即立刻停止当前子串的匹配,对下一个子串继续匹配。如果当前子串匹配成功,我们返回当前子串的开始位置即可。如果所有子串都匹配失败,则返回−1。

  • 方法二:Knuth-Morris-Pratt 算法,简称KMP 算法

int strStr(char* haystack, char* needle) {
   
    int len1 = strlen(haystack);
    int len2 = strlen(needle);

    for (int i = 0; i + len2 <= len1; i++) {
     //注意i + len2
        bool flag = true;
        for (int j = 0; j < len2; j++) {
   
            if (haystack[i + j] != needle[j]) {
   
                flag = false;
                break;
            }
        }
        if (flag) {
   
            return i;
        }
    }
    return -1;
}

题目四:242. 有效的字母异位词

题解:

  • 方法一:排序。t 是 s 的异位词等价于两个字符串排序后相等。因此我们可以对字符串 s 和 t分别排序,看排序后的字符串是否相等即可判断。此外,如果 s 和 t 的长度不同,t 必然不是 s 的异位词。
  • 方法二:哈希表。 从另一个角度考虑,t 是 s 的异位词等价于两个字符串中字符出现的种类和次数均相等。由于字符串只包含 26个小写字母,因此我们可以维护一个长度为 26 的频次数组 table,先遍历记录字符串 s 中字符出现的频次,然后遍历字符串 t,减去table 中对应的频次,如果出现 table[i]<0,则说明 t 包含一个不在 s 中的额外字符,返回 false 即可。
bool isAnagram(char* s, char* t) {
   
    int len1 = strlen(s);
    int len2 = strlen(t);

    if (len1 != len2) {
   
        return false;
    }

    int table[26] = {
   0};
    for (int i = 0; i < len1; i++) {
   
        table[s[i] - 'a']++;
    }

    for (int i = 0; i < len2; i++) {
   
        table[t[i] - 'a']--;
        if (table[t[i] - 'a'] < 0) {
    //在长度相等的情况下,若不互为字母异位词,一定会存在某个字母数量使table[i] < 0;若用table[i] > 0则无法判断;
            return false;
        }
    }

    return true;
}

题目五:459. 重复的子字符串

题解:
方法一:枚举
在这里插入图片描述

bool repeatedSubstringPattern(char* s) {
   
    int len = strlen(s);
    for (int i = 1; i * 2 <= len; i++) {
   
        if (len % i == 0) {
     //条件一,i为分母,不能为0
            bool match = true;
            for (int j = i; j < len;j++) {
   
                if (s[j] != s[j - i]) {
     //条件三,i相当于一个周期
                    match = false;
                    break;
                }
            }
            if (match) {
   
                return true;
            }
        }
    }
    return false;
}

方法二:字符串匹配
在这里插入图片描述

bool repeatedSubstringPattern(char* s) {
   
    int len = strlen(s);
    char k[2 * len + 1]; // 计算拼接后的字符数另外需再加1才够空间存放末尾的空字符
    k[0] = 0;
    strcat(k, s); // char *strcat(char *dest, const char *src) 把 src所指向的字符串追加到 dest 所指向的字符串的结尾。
    strcat(k, s); // 将两个 s 连在一起
    return strstr(k + 1, s) - k !=len; // strstr()函数搜索一个字符串在另一个字符串中的第一次出现,返回的是匹配成功的字符串以及后面的字符串
    // k + 1:k字符串舍去前面1个字符
}

疑问:strstr(k + 1, s) - k是什么用法?

题目六:283. 移动零

题解
方法一:双指针
使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。

右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。

注意到以下性质:

  • 左指针左边均为非零数;
  • 右指针左边直到左指针处均为零。

因此每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变。

注意:函数传参不同,解决方法不同!

void swap(int *a,int *b){
   
    int t = *a;
    *a = *b;
    *b = t;
}
//很像冒泡哎,把0往后冒
void moveZeroes(int* nums, int numsSize) {
   
    int left = 0,right = 0;
    while(right < numsSize){
   
        if(nums[right] != 0){
   
            swap(nums + left,nums + right); //传的是地址
            left++;
        }
        right++;
    }
}
class Solution {
   
    public void moveZeroes(int[] nums) {
   
        int n = nums.length, left = 0, right = 0;
        while (right < n) {
   
            if (nums[right] != 0) {
   
                swap(nums, left, right);
                left++;
            }
            right++;
        }
    }

    public void swap(int[] nums, int left, int right) {
   
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }
}

题目七: 66. 加一

题解
当我们对数组 digits 加一时,我们只需要关注 digits 的末尾出现了多少个 9 即可。我们可以考虑如下的三种情况:

  • 如果 digits 的末尾没有 9,例如[1,2,3],那么我们直接将末尾的数加一,得到 [1,2,4] 并返回;
  • 如果 digits 的末尾有若干个9,例如 [1,2,3,9,9],那么我们只需要找出从末尾开始的第一个不为 9的元素,即3,将该元素加一,得到 [1,2,4,9,9]。随后将末尾的 9 全部置零,得到[1,2,4,0,0] 并返回。
  • 如果 digits 的所有元素都是9,例如[9,9,9,9,9],那么答案为 [1,0,0,0,0,0]。我们只需要构造一个长度比digits 多 1 的新数组,将首元素置为 1,其余元素置为 0 即可。

只需要对数组 digits 进行一次逆序遍历,找出第一个不为 9 的元素,将其加一并将后续所有元素置零即可。如果 digits 中所有的元素均为 9,那么对应着「思路」部分的第三种情况,我们需要返回一个新的数组。

int* plusOne(int* digits, int digitsSize, int* returnSize) {
   
    //包括了情况1,情况2,情况3的置0部分
    for(int i = digitsSize - 1;i >= 0;i--){
   //倒着进行检查
        if(digits[i] != 9){
   
            digits[i]++;
            break;
        }else{
   
            digits[i] = 0;
        }
    } 

    if(digits[0] == 0){
   //当数字全为9时
        int *temp;
        int size = digitsSize + 1;
        temp = (
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值