leetcode-字符串-简单-C-第一部分

序号13

题目
解析:由后一个字母和前一个字母大小比较,决定前一个字母的正负

  1. 模拟
    存储字母对应值,可以用数组保存,也可以函数 switch 返回
int romanToInt(char * s){
    int value[150] = { 0 };
    value['I'] = 1; value['V'] = 5; value['X'] = 10;
    value['L'] = 50; value['C'] = 100; value['D'] = 500;
    value['M'] = 1000;
    int sum = 0;
    int preNum = value[s[0]];
    int num;

    for (int i = 1; s[i] != '\0'; i++)
    {
        num = value[s[i]];
        if (preNum < num)
            sum -= preNum;
        else
            sum += preNum;
        preNum = num;
    }
    sum += preNum;  //最后一个字母直接加
    return sum;
}

序号14

题目:编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。

解析

  1. 模拟
    逐个比较所有字符串的前缀
int isSame(char** strs, int strsSize, int pos)
{
    for (int i = 0; i < strsSize - 1; i++)
    {
        if (strs[i][pos] != strs[i+1][pos])
            return 0;
    }
    return 1;
}

char * longestCommonPrefix(char ** strs, int strsSize){
    if (strsSize == 0)
        return "";
    
    int len = strlen(strs[0]);
    char* ans = (char*)malloc(sizeof(char) * (len+1));  //还有一个\0
    strcpy(ans, strs[0]);  //最长前缀肯定在其中
    int cnt = 0;
    
    for (int i = 0; i < len; i++)
    {
        if (isSame(strs, strsSize, i))
            cnt++;
        else 
            break;    
    }
    ans[cnt] = '\0';  //截取字符串
    return ans;
}

序号20

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

解析:


  1. 现在的字符与栈顶的字符比较,匹配则出栈,否则入栈当前的字符
    最后判断栈是否为空
bool isValid(char * s){
    if (s[0] == '\0')
        return true;

    char stack[100000];  //测试点没这么多... 也可以用链栈
    stack[0] = s[0];
    int top = 0;
    char ch;

    for (int i = 1; s[i] != '\0'; i++)
    {
        if (top == -1)
            stack[++top] = s[i];
        else
        {
            ch = stack[top];
            if ((ch == '(' && s[i] == ')') || (ch == '[' && s[i] == ']')
                || (ch == '{' && s[i] == '}'))
                top--;
            else
                stack[++top] = s[i];
        } 
    }
    if (top == -1)
        return true;
    else
        return false;
}

序号38

题目题目
解析

  1. 打表法
    最后的答案过于长,可以直接打表,最后判断输出
  2. 模拟
    按照要去生成数组
char* countAndSay(int n) {
    if (n == 1)
        return "1";

    char str[5000];
    strcpy(str, countAndSay(n - 1));
    int len = strlen(str);
    char cnt[50];
    static char ans[5000];
    strcpy(ans, "");
    for (int i = 0; i < len;)
    {
        int j = i + 1;
        while (j < len && str[j] == str[i])
            j++;
        sprintf(cnt, "%d", j - i);
        strcat(ans, cnt);
        char ch[2] = { str[i], '\0' };
        strcat(ans, ch);
        i = j;
    }
    return ans;
}

序号58

题目:给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s,返回其最后一个单词的长度。如果字符串从左向右滚动显示,那么最后一个单词就是最后出现的单词。
如果不存在最后一个单词,请返回 0 。
说明:一个单词是指仅由字母组成、不包含任何空格字符的 最大子字符串。

解析

  1. 模拟
    倒着遍历字符串,找单词
int lengthOfLastWord(char* s) {
	int len = strlen(s);
	int cnt = 0;
	for (int i = len - 1; i >= 0; --i)
	{
		while (i >= 0 && s[i] != ' ')
		{
			--i;
			++cnt;
		}
		if (cnt != 0)
			return cnt;
	}
	return 0;
}

序号67

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

解析

  1. 模拟加法
char* addBinary(char* a, char* b) {
	int lenA = strlen(a);
	int lenB = strlen(b);
	int longLen, shortLen;
	char one[1000], two[1000];
	if (lenA > lenB)
	{
		strcpy(one, a);
		strcpy(two, b);
		longLen = lenA;
		shortLen = lenB;
	}
	else
	{
		strcpy(one, b);
		strcpy(two, a);
		longLen = lenB;
		shortLen = lenA;
	}
	int carry = 0;
	int temp, j;
	for (int i = shortLen - 1; i >= 0; --i)
	{
		j = longLen - (shortLen - i);
		temp = carry + two[i] - '0' + one[j] - '0';
        carry = temp / 2;
        one[j] = temp % 2 + '0';
	}
    for (j = j - 1; carry == 1 && j >= 0; --j)
    {
        temp = 1 + one[j] - '0';
        carry = temp / 2;
        one[j] = temp % 2 + '0';
    }
	char* ans = (char*)malloc(sizeof(char) * (longLen + 2));
	if (carry == 1)
	{
		strcpy(ans, "1");
		strcat(ans, one);
	}
    else
        strcpy(ans, one);
	return ans;
}

序号125

题目:给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。

解析

  1. 模拟
    先转换为只有字母和数字字符的字符串,并且都转为小写字母。再判断回文
bool isPalindrome(char* s) {
	static char dest[1000000];
	int len = 0;
	for (int i = 0; s[i] != '\0'; ++i)
	{
		if (isdigit(s[i]))
			dest[len++] = s[i];
		else if (isalpha(s[i]))
			dest[len++] = tolower(s[i]);
	}
	for (int i = 0; i < len/2; ++i)
	{
		if (dest[i] != dest[len - 1 - i])
			return false;
	}
	return true;
}

:开很大的数组,用 static

序号344

题目:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

解析

  1. 模拟
    交换头尾字符即可
void reverseString(char* s, int sSize) {
	char ch;
	for (int i = 0; i < sSize / 2; ++i)
	{
		ch = s[i];
		s[i] = s[sSize - 1 - i];
		s[sSize - 1 - i] = ch;
	}
}

序号345

题目:编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

解析

  1. 双指针
    针对元音字母反转,需要双指针进行判断再反转
bool isYuan(char c)
{
	switch (c)
	{
	case 'a':
	case 'A':
	case 'e':
	case 'E':
	case 'i':
	case 'I':
	case 'o':
	case 'O':
	case 'u':
	case 'U':
		return true;
	}
	return false;
}

char* reverseVowels(char* s) {
	int len = strlen(s);
	int i = 0;
	int j = len - 1;
	char ch;
	while (i < j)
	{
		if (isYuan(s[i]) && isYuan(s[j]))
		{
			ch = s[i];
			s[i] = s[j];
			s[j] = ch;
			++i;
			--j;
		}
		else if (!isYuan(s[i]))
			++i;
		else
			--j;
	}
	return s;
}

序号383

题目:给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成。如果可以构成,返回 true ;否则返回 false。
(题目说明:为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,组成单词来表达意思。)

解析

  1. 散列记录
    在第二个字符串中找到所需字母及其数量即可,不需要顺序
bool canConstruct(char* ransomNote, char* magazine) {
	int hash[128] = { 0 };
	for (int i = 0; ransomNote[i] != '\0'; ++i)
		hash[ransomNote[i]]++;
	for (int i = 0; magazine[i] != '\0'; ++i)
	{
		if (hash[magazine[i]] != 0)
			hash[magazine[i]]--;
	}
	for (int i = 0; i < 128; ++i)
	{
		if (hash[i] != 0)
			return false;
	}
	return true;
}

序号387

题目:给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

解析

  1. 散列记录
    记录每个字母出现的次数,找到次数为 1 的,直接返回
int firstUniqChar(char* s) {
	int hash[128] = { 0 };
	for (int i = 0; s[i] != '\0'; ++i)
		hash[s[i]]++;
	for (int i = 0; s[i] != '\0'; ++i)
	{
		if (hash[s[i]] == 1)
			return i;
	}
	return -1;
}

序号392

题目:给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

解析:

  1. 模拟
    只要按顺序找到所有字符就可以
bool isSubsequence(char * s, char * t){
    int len1 = strlen(s);
    int len2 = strlen(t);
    int i = 0;
    int j = 0;

    while (i < len1 && j < len2)
    {
        if (s[i] == t[j])
            i++;
        j++;
    }
    if (i == len1)
        return true;
    else 
        return false;
}

序号415

题目:给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
注意:
num1 和num2 的长度都小于 5100.
num1 和num2 都只包含数字 0-9.
num1 和num2 都不包含任何前导零。
你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式。

解析

  1. 模拟
    注意字符串的赋值即可
char* addStrings(char* num1, char* num2) {
	char one[5102], two[5102];
	int oneLen, twoLen;
	if (strlen(num1) > strlen(num2))
	{
		strcpy(one, num1);
		strcpy(two, num2);
		oneLen = strlen(num1);
		twoLen = strlen(num2);
	}
	else
	{
		strcpy(one, num2);
		strcpy(two, num1);
		oneLen = strlen(num2);
		twoLen = strlen(num1);
	}
	int carry = 0;
	int i = twoLen - 1;
	int j = oneLen - 1;
	int temp;
	for (; i >= 0; --i,--j)
	{
		temp = one[j] - '0' + two[i] - '0' + carry;
		carry = temp / 10;
		one[j] = temp % 10 + '0';
	}
	for (; carry == 1 && j >= 0; --j)
	{
		temp = one[j] - '0' + 1;
		carry = temp / 10;
		one[j] = temp % 10 + '0';
	}
    char* ans = (char*)malloc(sizeof(char) * (oneLen + 2));
	if (carry == 1)
	{
		strcpy(ans, "1");
		strcat(ans, one);
		return ans;
	}
    strcpy(ans, one);
    return ans;
}

序号434

题目:统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。
请注意,你可以假定字符串里不包括任何不可打印的字符。

解析

  1. 模拟
    寻找空格,计入单词
int countSegments(char* s) {
	int cnt = 0;
	int flag = 0;
	for (int i = 0; s[i] != '\0'; ++i)
	{
		if (s[i] != ' ')
		{
			if (flag == 0)
			{
				cnt++;
				flag = 1;
			}
		}
		else
			flag = 0;
	}
	return cnt;
}

序号443

题目:给定一组字符,使用原地算法将其压缩。
压缩后的长度必须始终小于或等于原数组长度。
数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。
在完成原地修改输入数组后,返回数组的新长度。

解析

  1. 双指针
    读、写指针以及一个记录起始读的指针。先写字符,再写次数
int compress(char* chars, int charsSize) {
	int read, write, startRead;
	read = write = startRead = 0;

	for (; read < charsSize; ++read)
	{
		if (read + 1 == charsSize || chars[read] != chars[read + 1])
		{
			chars[write++] = chars[startRead];
			if (read > startRead)
			{
				char temp[4] = "";
				sprintf(temp, "%d", read - startRead + 1);
				for (int i = 0; temp[i] != '\0'; ++i)
					chars[write++] = temp[i];
			}
			startRead = read + 1;
		}
	}
	return write;
}

序号520

题目:给定一个单词,你需要判断单词的大写使用是否正确。
我们定义,在以下情况时,单词的大写用法是正确的:
全部字母都是大写,比如"USA"。
单词中所有字母都不是大写,比如"leetcode"。
如果单词不只含有一个字母,只有首字母大写, 比如 “Google”。
否则,我们定义这个单词没有正确使用大写字母。

解析

  1. 模拟
    用数学翻译题目,大写字母出现 0 次、1次且是首字母、全部都是
bool detectCapitalUse(char * word){
    int cntUp = 0;
    int len = strlen(word);

    for (int i = 0; i < len; ++i)
    {
    	if (isupper(word[i]))
    		cntUp++;
    }
    if (cntUp == len || cntUp == 0 || (cntUp == 1 && isupper(word[0])))
    	return true;
    else
    	return false;
}	

序号521

题目:给定两个字符串,你需要从这两个字符串中找出最长的特殊序列。最长特殊序列定义如下:该序列为某字符串独有的最长子序列(即不能是其他字符串的子序列)。
子序列可以通过删去字符串中的某些字符实现,但不能改变剩余字符的相对顺序。空序列为所有字符串的子序列,任何字符串为其自身的子序列。
输入为两个字符串,输出最长特殊序列的长度。如果不存在,则返回 -1。

解析

  1. 逻辑分析
    若两个相同,返回 -1
    若长度相同且不同,则返回长度
    若长度不同,则返回最长的那个,那个必不是另一个的子序列
int findLUSlength(char * a, char * b){
    if (!strcmp(a, b))
        return -1;
    int lenA = strlen(a);
    int lenB = strlen(b);
    return lenA > lenB ? lenA : lenB;
}

序号541

题目:给定一个字符串和一个整数 k,你需要对从字符串开头算起的每个 2k 个字符的前k个字符进行反转。如果剩余少于 k 个字符,则将剩余的所有全部反转。如果有小于 2k 但大于或等于 k 个字符,则反转前 k 个字符,并将剩余的字符保持原样。

解析
1.模拟
先反转最大 k 个,然后前移 k 个位置

void Reverse(char *str, int left, int right)
{
	int i = left;
	int j = right;
	while (i < j)
	{
		char temp = str[i];
		str[i] = str[j];
		str[j] = temp;
		++i;
		--j;
	}
}
 
char * reverseStr(char * s, int k){
	int len = strlen(s);
	for (int i = 0; i < len;)
	{
		if (i + k < len)
			Reverse(s, i, i + k - 1);
		else
			Reverse(s, i, len - 1);
		i += 2*k;
	}
    return s;
}

序号551

题目:给定一个字符串来代表一个学生的出勤记录,这个记录仅包含以下三个字符:
‘A’ : Absent,缺勤
‘L’ : Late,迟到
‘P’ : Present,到场
如果一个学生的出勤记录中不超过一个’A’(缺勤)并且不超过两个连续的’L’(迟到),那么这个学生会被奖赏。
你需要根据这个学生的出勤记录判断他是否会被奖赏。

解析

  1. 模拟
    处理连续的 L,当前是 L,计数 +1;不是,计数归 0
bool checkRecord(char * s){
	int cntA = 0;
	int ctCntL = 0;

	for (int i = 0; s[i] != '\0'; ++i)
	{
		if (s[i] == 'L')
		{
			++ctCntL;
			if (ctCntL > 2)
				return false;
		}
		else
		{
			if (s[i] == 'A')
				++cntA;
			ctCntL = 0;
		}
	}
	if (cntA <= 1)
		return true;
	else
		return false;
}

序号557

题目:给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

解析

  1. 模拟
    寻找空格,然后反转单词
void Reverse(char* left, char* right)
{
	while (left < right)
	{
		char temp = *left;
		*left = *right;
		*right = temp;
		++left;
		--right;
	}
}

char* reverseWords(char* s) {
	char* left = s;
	char* right = strchr(s, ' ');
	int len = strlen(s);
	while (right)
	{
		Reverse(left, right - 1);
		left = right + 1;
		right = strchr(left, ' ');
	}
	Reverse(left, s + len - 1);
	return s;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值