LeetCode之字符串

1 在一个字符串中查找另一个字符串的位置

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。

  • 示例 :
    输入:haystack = “hello”, needle = “ll”
    输出:2
int strStr(char* haystack, char* needle) {
    int n = strlen(haystack), m = strlen(needle);
    for (int i = 0; i + m <= n; i++) {
        bool flag = true;
        for (int j = 0; j < m; j++) {
            if (haystack[i + j] != needle[j]) {
                flag = false;
                break;
            }
        }
        if (flag) {
            return i;
        }
    }
    return -1;
}

2 罗马数字转整数

字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

int romanToInt(char * s){
    int table[26];
    table['I'-'A'] = 1;
    table['V'-'A'] = 5;
    table['X'-'A'] = 10;
    table['L'-'A'] = 50;
    table['C'-'A'] = 100;
    table['D'-'A'] = 500;
    table['M'-'A'] = 1000;
    int n = strlen(s);
    int ans = 0;
    for(int i =0; i < n; ++i){
        int value = table[s[i] - 'A'];
        if(i < n-1 && value < table[s[i+1] - 'A']){
            ans -= value;
        }
        else{
            ans += value;
        }
    }
    return ans;
}

3 查找字符串数组中的最长公共前缀

  • 示例 1:
    输入:strs = [“flower”,“flow”,“flight”]
    输出:“fl”

  • 示例 2:
    输入:strs = [“dog”,“racecar”,“car”]
    输出:“”
    解释:输入不存在公共前缀。

char * longestCommonPrefix(char ** strs, int strsSize){
    if(strsSize == 0)
        return "";
    if(strsSize == 1)
        return strs[0];
    char *ret = (char *)malloc(sizeof(char) * 200);
    int i,j;
    for(j = 0; ; j++) {
        if(strs[0][j]=='\0' || strs[1][j]=='\0'){
            ret[j] = '\0';
            break;
        }
        if(strs[0][j] == strs[1][j]){
            ret[j] = strs[0][j];
            ret[j+1] = '\0';
        }
        else{
            ret[j] = '\0';
            break;
        }
    }
    for(i = 2; i < strsSize; i++){
        if(ret[0] == '\0' || strs[i][0] == '\0')
            return "";

        for(j = 0; strs[i][j]!= '\0' || ret[j] != '\0'; j++){
            if(strs[i][j] != ret[j]){
                ret[j] = '\0';
                break;
            }
        }
    }
    return ret;
}

4 有效的括号

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

char pairs(char a)
{
    if(a == ']')
        return '[';
    if(a == '}')
        return '{';
    if(a == ')')
        return '('; 
    return 0;
}

bool isValid(char * s){
    int n = strlen(s);
    if(n % 2 == 1)
        return false;
    int stack[n+1], top =0 ;
    for(int i=0; i<n ; i++){
        char ch = pairs(s[i]);
        if(ch){
            if(top == 0 || stack[top-1] != ch) {
                return false;
            }
            top--;
        } else {
            stack[top++] = s[i];
        }
    }
    return top == 0;  
}

5 最后一个单词的长度

给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中最后一个单词的长度。

int lengthOfLastWord(char * s){
    int n = strlen(s);
    int k = 0, N = 0;
    for(int i = n-1; i >= 0; i--){
        if(s[i] == ' '){
            continue;
        }
        else{
            N = i;
            break;
        }
    }
    for(int i = N; i >= 0; i--){
        if(s[i] != ' '){
            k++;
        }
        else{
            return k;
        }
    }
    return k;
}

6 二进制求和

给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1 和 0。

思路:首先将俩字符串翻转,取俩字符串中长度较大的,定义一个进位标志,按位带进位进行模2计算,在对进位进行处理。

void reverse(char * s)
{
    int len = strlen(s);
    for(int i = 0; i< len / 2; i++){
        char t = s[i];
        s[i] = s[len-i-1];
        s[len-i-1] = t;
    }    
}


char * addBinary(char *a, char *b){
    reverse(a);
    reverse(b);
    
    int len_a = strlen(a);
    int len_b = strlen(b);

    int n = fmax(len_a, len_b), carry=0, len=0;
    char *ans = (char *)malloc(sizeof(char)*(n+2));
    for(int i = 0; i < n; ++i){
        carry += i < len_a ? (a[i] == '1') : 0;
        carry += i < len_b ? (b[i] == '1') : 0;
        ans[len++] = carry % 2 + '0';
        carry /= 2;
    }

    if(carry){
        ans[len++] = '1';
    }
    ans[len] = '\0';
    reverse(ans);

    return ans;
}

7 翻转字符串

输入: " hello world! "
输出: “world! hello”
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。

思路:首先申请一块内存用于存放结果。定义两个指针left,right。left 先从尾部开始往前走,走到非空字符,将位置交给 right,left 继续往前走到空字符,left+1 到 right 就是一个完整的单词,复制。最后检查在末尾加上\0.

char* reverseWords(char* s) {
    int len = strlen(s);
    char* res = (char*)malloc(sizeof(char) * (len + 1));
    int cur = 0, index = 0;
    int left = len - 1, right = len - 1;
    while (left >= 0) {
        if (s[left] == ' ') {
            left--;
        } else {
            right = left;
            while (left >= 0 && s[left] != ' ') {
                left--;
            }
            cur = left + 1;
            while (cur <= right) {
                res[index++] = s[cur++];
            }
            res[index++] = ' ';
        }
    }
    if (index > 0 && res[index - 1] == ' ') {
        /* 原字符串有字符的情况 */
        res[index - 1] = '\0';
    } else {
        /* 原字符串为空或者全为空格的情况 */
        res[index] = '\0';
    }
    return res;
}

解法2:栈
思路:从尾部入栈然后出栈拷贝到结果数组中。

char* reverseWords(char* s) {
    int n = strlen(s);
    if(n == 0)
        return s;
    char* ret = (char*)malloc(sizeof(char) * (n+1));
    char* stack = (char*)malloc(sizeof(char) * (n+1));
    int top = 0, index = 0;
    for(int i = n - 1; i >= 0; i--){
        while(s[i] == ' ')
            i--;
        while(i >= 0 && s[i] != ' ')
            stack[top++] = s[i--];
        while(top > 0)
            ret[index++] = stack[--top];
        ret[index++] = ' ';    
    } 

    while(index >= 0 && ret[index-1] == ' '){
        index -- ;
    }
    ret[index] = '\0';
    return ret;
}

8 替换空格

将字符串中的空格替换为 %20

char* replaceSpace(char* s){
    int n = strlen(s);
    int index = 0;
    char * res = (char *)malloc((3*n+1)*sizeof(char));
    for(int i = 0; i < n; i++){
        if(s[i] == ' '){
            res[index++] = '%';
            res[index++] = '2';
            res[index++] = '0';
        } else {
            res[index++] = s[i];
        }      
    }
    res[index++] = '\0';
    return res;
}

9 查找字符串中第一个只出现一次的字符

思路:
首先建立一个新的数组用来保存每个字符出现的次数,接着遍历数组,查找第一个为 1 的位置,输出。

小tips:
如何统计字符串中字符出现的次数?
新建一个数组,利数组的索引来确定位置,值来统计次数。

char firstUniqChar(char* s){
    int n = strlen(s);
    if (n == 0)
        return ' ';
    
    int res[26] = {0};

    for(int i = 0; i < n; i++){
        res[s[i]-'a']++;
    }

    for(int i = 0; i < n; i++){
        if(res[s[i] - 'a'] == 1)
        {
            return s[i];
        }
    }
    
    return ' ';
}

10 左旋转字符串

  • 输入: s = “lrloseumgh”, k = 6
    输出: “umghlrlose”
char* reverseLeftWords(char* s, int n){
    int len = strlen(s);
    char *c = (char *)malloc((len+1)*sizeof(char));
    
    for(int i = 0; i<len-n; i++){
        c[i] = s[n+i];
    }
    for(int i = 0; i < n; i++){
        c[len-n+i] = s[i];
    }
    c[len]='\0';
    return c;
}

11 字符串的排列***

  • 输入:s = “abc”
    输出:[ “abc”, “acb”, “bac”, “bca”, “cab”, “cba”]

思路:回溯法
将问题看成一个n个字符的排列问题,定义一个递归函数backtrack(i, perm) 表示当前排列为 perm, 下一个待填入的空位是第 i 个空位,当 i=n 时,说明已经完成了排列, 将 perm 放入答案数组中,递归结束。
当 i < n 时,此时需要考虑第 i 个空位填入一个未被填入的字符,我们可以用一个标记数组 vis 来标记已经被填过的字符,在填入第 i 个字符时,我们首先要遍历 n 个字符,找出没有被标记的字符填入 ,即调用 backtrack(i+1, perm)
当出现重复字符的时候,会出现重复的现象,我们可以考虑首先对字符串进行一个排序,保证重复的字符串都相邻,在递归函数中,我们限制每次填入的字符一定是这个字符所在的字符集合中 自左向右第一个未被填入的字符
实现如下:if(vis[j] || (j > 0 && !vis[j-1] && s[j-1] == s[j])) { continue; }

void backtrack(char** rec, int* recSize, int* vis, char* s, int i, int n, char* perm)
{
    if(i == n  {
        char* tmp = malloc(sizeof(char)*(n+1));
        strcpy(tmp, perm);
        rec[(*recSize)++] = tmp;
        return;
    }

    for(int j = 0; j < n; j++) {
        if(vis[j] || (j > 0 && !vis[j-1] && s[j-1] == s[j])) { continue; }
        vis[j] = true;
        perm[i] = s[j];
        backtrack(rec, recSize, vis, s, i+1, n, perm);
        vis[j] = false;
    }
}

int cmp(char* a, char* b){
    return *a - *b;
}

char** permutation(char* s, int* returnSize){
    int n = strlen(s);

    int recMaxSize = 1;
    for(int i = 2; i <= n; i++){
        recMaxSize *= i;
    }

    char ** rec = malloc(sizeof(char*)*recMaxSize);
    *returnSize = 0;

    int vis[n];
    memset(vis, 0, sizeof(vis));
    
    char perm[n+1];
    perm[n] = '\0';

    qsort(s, n, sizeof(char),cmp);
    backtrack(rec, returnSize, vis, s, 0, n, perm);
    
    return rec;
}

12 把数组排成最小的数

  • 输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
int compare(const void *a, const void *b)
{
    char num1[24];
    char num2[24];

    sprintf(num1, "%d%d", *(int *)a, *(int *)b);
    sprintf(num2, "%d%d", *(int *)b, *(int *)a);
    return strcmp(num1, num2);
}

char* minNumber(int* nums, int numsSize){
    char *res = (char *)malloc(sizeof(char) * 1200);
    char *p = res;

    qsort(nums, numsSize, sizeof(int), compare);
    for (int i = 0; i < numsSize; i++)
        p += sprintf(p, "%d", nums[i]);
    *p = '\0';
    return res;
}

13 把数字翻译成字符串

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

  • 示例 1:
    输入: 12258
    输出: 5
    解释: 12258有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”, “mcfi"和"mzi”
int translateNUM(int num)
{
	int *nums = (int *)malloc(sizeof(int)*20), numSize = 0;
	int *dp = (int *)malloc(sizeof(int)*20);
	
	while(num<9){
		nums[numSize++] = num % 10;
		num = (num - num%10) /10;
	}
	nums[numSize++] = num;

	for(int left=0, right=numSize-1;left<right;left++,right--){
		int t = nums[left];
		nums[left] = nums[right];
		nums[right] = t;
	}
	
	dp[0]=1;
	dp[1]=(nums[0]*10+nums[1] < 26 && nums[0]*10+nums[1] > 9)? dp[0]+1:dp[0];
	for(int i=2; i<numSize; i++){
		dp[i]=(nums[i-1]*10+nums[i] < 26 && nums[i-1]*10+nums[i] > 9)? dp[i-1]+dp[i-2]:dp[i];
	}
	return dp[numSize-1];
}

总结:如何取出一个整数的每一位
首先定一个新的数组来保存,依次取出个位十位百位…倒置数组。

	while(num<9){
		nums[numSize++] = num % 10;
		num = (num - num%10) /10;
	}
	nums[numSize++] = num;

	for(int left=0, right=numSize-1;left<right;left++,right--){
		int t = nums[left];
		nums[left] = nums[right];
		nums[right] = t;
	}

14 最长不含重复字符的子字符串

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

  • 示例 3:
    输入: “pwwkew”
    输出: 3
    解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
    请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

思想:首先做一个哈希映射统计每个字符出现的次数
定义left 和 right 两个指针,当有某个字符的次数超过1,则左指针指向的字符次数减一并且左移。

#define MAX 128
int alp[MAX];
int lengthOfLongestSubstring(char* s){
    int right = 0, left = 0;
    int max = 0, tmp;
    memset(alp, 0, sizeof(alp));

    while (s[right] != '\0') {
        alp[s[right]]++;
        while (alp[s[right]] > 1) {
            alp[s[left]]--;
            left++;
        }
        tmp = right - left + 1;
        max = (max > tmp ? max : tmp);
        right++;
    }
    return max;
}

15 将字符串转化为整数

需要考虑空格、正负、溢出

int strToInt(char* s){
    int n = strlen(s);
    if(n == 0)
        return 0;
    int flag = 1;
    while(*s == ' '){
        s++;
    }
    if(*s == '-'){
        flag = -1;
        s++;
    } else if (*s == '+'){
        s++;
    }
    double sum=0;
    while(*s >= '0' && *s <= '9'){
        sum = sum * 10 + (*s - '0');
        if(sum * flag >= INT_MAX){
            return INT_MAX;
        } else if (sum * flag <= INT_MIN){
            return INT_MIN;
        }
        s++;
    }
    return flag*sum;
}

总结一个技巧
如何将一个字符串转化为整数

sum = sum*10 + (*s - '0')
s++

16 判断字符串是否为数字

能成为数字的字符的条件:
纯数字、+/- 1.5、3.12、2E5、-5E3、.5

思路:
首先定义几个falg,用来检测数字、科学计数、点、符号。首先处理前导空格,遍历字符串,判断当前char的类型。如果是数字跳过;如果是科学计数法,判断之前是否出现科学计数和数字,若咩有则返回FALSE,将eFlag置位,清空其他标志位;如果是正负号,判断之前是否有数字、E、点、正负号,若有返回FALSE,Flag置位;如果是点,判断之前是否有点、E,若有返回FALSE,Flag置位;如果出现空格说明是后面多余的空格直接结束循环;如果都不是,直接返回FALSE。接着处理一下后置空格。最后判断遍历索引是否等于字符串长度而且有数字。

bool isNumber(char* s) {
    int n = strlen(s);
    bool numFlag=false, eFlag=false, dotFlag=false, signFlag=false;
    int index=0;
    while(s[index] == ' '){
        index ++;
    }

    while(index < n) {
        while(index < n && '0' <= s[index] && s[index] <= '9') {
            numFlag = true;
            index ++; 
        }

        if(index == n)
            break;

        if(s[index] == 'e' || s[index] == 'E') {
            if(eFlag == true || !numFlag)
                return false;
            eFlag = true;
            numFlag = false; dotFlag = false; signFlag = false;
        } 
        else if (s[index] == '+' || s[index] == '-') {
            if(numFlag || signFlag || dotFlag)
                return false;
            signFlag = true;
        } 
        else if (s[index] == '.') {
            if(eFlag || dotFlag)
                return false;
            dotFlag = true;
        }
        else if (s[index] == ' ') {
            break;
        }
        else {
            return false;
        }
        index++;
    }
    while(index < n && s[index] == ' '){
        index++;
    }
    return numFlag && (index == n);   
}

17 反转数字

class Solution:
    def reverse(self , x: int) -> int:
        # write code here
        x = str(x)
        if(x[0] == '-'):
            a = int('-' + x[1:][::-1])
        else:
            a = int(x[::-1])
        return a if -2147483648 < a < 2147483648 else 0
# [::-1]表示从右向左全部
int reverse(int x ) {
    long n = 0;
    while(x != 0){
        n = n *10 + x %10;
        x = x / 10;
    }
    if(n < -2147483648  || n > 2147483648){
        return 0;
    }
    return n;
}

18 求平方根(二分查找)

int Sqrt(int x ) {
    // write code here
    if(x < 2)
        return x;
    long left = 0,right = x/2;
    while(left <= right){
        long mid = left + ((right - left)/2);
        if(mid*mid <= x && (mid+1)*(mid+1) > x)
           return (int)mid;
        else if(mid*mid < x)
            left = mid + 1;
        else right = mid - 1;
        }
        return -1;
}
class Solution:
    def sqrt(self , x: int) -> int:
        med = int(x/2)
        while pow(med, 2)>x:
            med = int(med/2)
        med = med+1
        while pow(med, 2)<=x:
            med += 1
        return int(med-1)

19 旋转字符串

A字符串从中间分开在拼接起来能得到B字符串则 TRUE

class Solution:
    def solve(self , A: str, B: str) -> bool:
        if A == B: return True
        if len(A) != len(B): return False
        return A in B+B
class Solution:
    def solve(self , A: str, B: str) -> bool:
        if A == B: return True
        if len(A) != len(B): return False
        for i in range(1,len(A)):
            c=[]
            for j in range(i, len(A)):
                c.append(A[j])
            for k in range(0, i):
                c.append(A[k])
            if(c == list(B)):
           #if(''.join(c) == B):
                return True
        return False
        
class Solution:
    def solve(self , A: str, B: str) -> bool:
        if A == B: return True
        if len(A) != len(B): return False
        for i in range(1,len(A)):
            c = ''
            for j in range(i, len(A)):
                c = c + A[j]
            for k in range(0, i):
                c = c + A[k]
            if(c == B):
                return True
        return False
        
# 新知识
注意 python中的字符串与列表
python中 list 与 string 的互换
list(<str>) 
''.join(<list>)

20 回文排列

给定一个字符串,编写一个函数判定其是否为某个回文串的排列之一。

class Solution:
    def canPermutePalindrome(self, s: str) -> bool:
        dic = defaultdict(int)
        for x in s:
            dic[x] += 1
        odd = 0
        for val in dic.values():
            if val % 2 == 1:
                odd += 1
                if odd > 1:
                    return False
        return True

21 HJ65 查找两个字符串a,b中的最长公共子串

while 1:
    try:
        str1, str2 = input(), input()
        
        if len(str1) > len(str2):
            str1, str2 = str2, str1
        
        m, n = len(str1), len(str2)
        dp = [0] * (n+1)
        max_, index = 0, 0
        
        for i in range(1, m+1):
            for j in range(n, 0, -1):
                if str1[i-1] == str2[j-1]:
                    dp[j] = dp[j-1] + 1
                    if dp[j] > max_:
                        max_ = dp[j]
                        index = j
                else:
                    dp[j] = 0
                    
        print(str2[index - max_: index]) 
    except:
        break
while 1:
    try:
        str1, str2 = input(), input()
        m, n = len(str1), len(str2)
        if m > n:
            str1, str2 = str2, str1
        res = []
        s = ''      
        for i in range(m):
            for j in range(i+1, m+1):
                if str1[i:j] in str2:
                    res.append(str1[i:j])                    
        for x in res:
            if len(x) > len(s):
                s = x                    
        print(s)
    except:
        break

22 HJ71 字符串通配符

实现如下2个通配符:
:匹配0个或以上的字符(注:能被和?匹配的字符仅由英文字母和数字0到9组成,下同)
?:匹配1个字符

def match(p, s):
    m, n = len(p), len(s)
    
    dp = [[False] *(n+1) for _ in range(m+1)]
    
    dp[0][0] = True
    
    for i in range(1, m+1):
        if p[i-1] == '*':
            dp[i][0] = True
        else:
            break
    
    for i in range(1, m+1):
        for j in range(1, n+1):
            if p[i-1] == '*':
                dp[i][j] = dp[i-1][j] or dp[i][j-1]
            elif p[i-1] == "?" and s[j-1].isalnum():
                dp[i][j] = dp[i-1][j-1]
            elif s[j-1] == p[i-1]:
                dp[i][j] = dp[i-1][j-1]
                
    return dp[m][n]

while 1:
    try:
        s1 = input().lower()
        s2 = input().lower()
        
        if match(s1, s2):
            print('true')
        else:
            print('false')
    except:
        break

23 HJ36 字符串加密

输入两个字符串,先将第一个去重然后按照字母顺序表在后面加上前边没有出现过的制作一个新的字母表,按照第二个字母表的顺序找到对应的输出。

key:
注意学习下如何生成26个字母的表

while 1:
    try:
        s1, s2 = input(), input()
        s = ''
        table = [chr((ord('a'))+i) for i in range(26)]
        
        for x in s1:
            if x not in s:
                s += x
        for x in table:
            if x not in s:
                s += x
        
        encode_table = {}
        for i in range(len(s)):
            encode_table[table[i]] = s[i]
        res = ''
        for x in s2:
            res += encode_table[x]  
        print(res)   
    except:
        break

你可能感兴趣的:(LeetCode,leetcode,算法,c语言)