编程基础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 = (