LeetCode刷题之字符串

面试题58 - II. 左旋转字符串

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例 1:

输入: s = “abcdefg”, k = 2 输出: “cdefgab” 示例 2:

输入: s = “lrloseumgh”, k = 6 输出: “umghlrlose”

限制:

1 <= k < s.length <= 10000

来源:力扣(LeetCode)
难度:easy
链接:https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:算法时间与空间复杂度:

时间复杂度:O(n) 空间复杂度:O(1)

实现步骤: 先研究字符串"hello world",如果我们要把前3个字符旋转,即变为"lo worldhel" 我们可以通过如下步骤实现:

1.以n为界限(该案例为3),把主串分成2个子串: “hel"和"lo world”
2.将2个子串逆序: 主串变为"leh"+“dlrow ol” = “lehdlrow ol”
3.间主串整体逆序 “lo worldhel”
4.函数调用返回

//将串s中前len个字符串逆序
void reverseStr(char* str, int len)
{
	if (!str || len == 1 || len == 0)
		return;

	//整体字符逆序
	char* head = str;
	char* tail = str + len - 1;
	while (head < tail)
	{
		*head = *head - *tail;
		*tail = *head + *tail;
		*head = *tail - *head;
		++head, --tail;
	}
}

char* reverseLeftWords(char* s, int n) {
	int len = strlen(s);
	if (!s || len == 0 || len == 1 || n >= len)
		return 0;
	reverseStr(s, n);
	reverseStr(s + n, len - n);
	reverseStr(s, len);

	return s;
}

1108. IP 地址无效化

给你一个有效的 IPv4 地址 address,返回这个 IP 地址的无效化版本。

所谓无效化 IP 地址,其实就是用 “[.]” 代替了每个 “.”。

示例 1:

输入:address = “1.1.1.1” 输出:“1[.]1[.]1[.]1” 示例 2:

输入:address = “255.100.50.0” 输出:“255[.]100[.]50[.]0”

来源:力扣(LeetCode)
难度:easy
链接:https://leetcode-cn.com/problems/defanging-an-ip-address
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:题目比较简单,根据ipv4地址的特点,在遇到每个’.'时特殊处理就好了。

char* defangIPaddr(const char* address) {
    if (!address || !address[0])
        return NULL;
    
    int len = strlen(address);
    char* res = (char*)malloc(len + 6 + 1);
    if (!res)
        return NULL;
    memset(res, 0, len + 6 + 1);

    int i = 0, index = 0;
    while (address[i])  //读到字符串'\0'结束
    {
        if (address[i] == '.')
        {
            res[index++] = '[';
            res[index++] = '.';
            res[index++] = ']';
        }
        else
        {
            res[index++] = address[i];
        }
        ++i;
    }

    return res;
}

709. 转换成小写字母

实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串
中的大写字母转换成小写字母,之后返回新的字符串。
示例 1:

输入: “Hello” 输出: “hello” 示例 2:

输入: “here” 输出: “here” 示例 3:

输入: “LOVELY” 输出: “lovely”

来源:力扣(LeetCode)
难度:easy
链接:https://leetcode-cn.com/problems/to-lower-case
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:常规思维

总结:
根据LeetCode上用户@Alfeim的总结:
大写变小写、小写变大写 : 字符 ^= 32; 若是字符是字母,大小写互换
大写变小写、小写变小写 : 字符 |= 32; 若字符是字母,一律变小写
小写变大写、大写变大写 : 字符 &= -33; 若字符是字母,一律变大写

char * toLowerCase(char * str){
    if(!str || !str[0])
        return NULL;
        
    int i = 0;
    while (str[i])
    {
        //发现是大写字母则转小写
        if(str[i] <= 'Z' && str[i] >= 'A')
            str[i] += ' ';//ASCII编码表种,大小写字母相差32,即对于' '字符的值
        i++;
    }
    return str;
}

804. 唯一摩尔斯密码词

国际摩尔斯密码定义一种标准编码方式,将每个字母对应于一个由一系列点和短线组成的字符串, 比如: “a” 对应 “.-”, “b” 对应
“-…”, “c” 对应 “-.-.”, 等等。

为了方便,所有26个英文字母对应摩尔斯密码表如下:

[".-","-…","-.-.","-…",".","…-.","–.","…","…",".—","-.-",".-…","–","-.","—",".–.","–.-",".-.","…","-","…-","…-",".–","-…-","-.–","–…"]
给定一个单词列表,每个单词可以写成每个字母对应摩尔斯密码的组合。例如,“cab” 可以写成 “-.-…–…”,(即 “-.-.” +
“-…” + ".-"字符串的结合)。我们将这样一个连接过程称作单词翻译。

返回我们可以获得所有词不同单词翻译的数量。

例如: 输入: words = [“gin”, “zen”, “gig”, “msg”] 输出: 2 解释: 各单词翻译如下: “gin”
-> “–…-.” “zen” -> “–…-.” “gig” -> “–…--.” “msg” -> “–…--.”

共有 2 种不同翻译, “–…-.” 和 “–…--.”.

注意:

单词列表words 的长度不会超过 100。 每个单词 words[i]的长度范围为 [1, 12]。 每个单词
words[i]只包含小写字母。

来源:力扣(LeetCode)
难度:easy
链接:https://leetcode-cn.com/problems/unique-morse-code-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:我写这个题的时候,灵机一闪,想到个绝妙的方法。
Morse密码的符号位’.‘和’-’,我们令其对于0和1,每当一个单词翻译完成后利用位运算将对于的Morse形式转化0和1并填充进一个32位的无符号数中,那么每个单词都显然对应一个数值,我称为code值,到时候我就只需检查数组就知道单词有几种翻译类型了。

//该函数获取单词对于Morse的code值
unsigned int getWordCode(char* morse)
{
    unsigned int wordCode = 0;
    int len = strlen(morse);
    for (int i = 0; i < len; ++i)
    {
        morse[i] == '.' ? wordCode << 1 : (wordCode | 1) << 1;
    }

    return wordCode;
}

//qsort排序需要一个函数指针,因此我们定义一个比较2数大小的函数
int compar(void* a, void* b)
{
    int aa = *((int*)a), bb = *((int*)b);
    int res = 0;

    return aa == bb ? res : (aa > bb ? res + 1 : res - 1);
}

//我们对排序完成的数组进行遍历,返回wordscode数组重复元素次数的最高值
int getCount(int* orderArr, int len)
{
    int tmpCount = 1;
    int maxCount = 1;

    for (int i = 1; i < len; ++i)
    {
        if (orderArr[i] == orderArr[i - 1])
        {
            ++tmpCount;
        }
        maxCount > tmpCount ? 1 : (maxCount = tmpCount);
        tmpCount = 1;
    }

    return maxCount;
}

int uniqueMorseRepresentations(const char** words, int wordsSize) {
    if (!wordsSize)
        return 0;

    char* morseTable[] = { ".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.." };

    //该数组是存储每个单词所绑定一个code值
    unsigned int* wordsCode = (int*)malloc(sizeof(int) * wordsSize);
    if (!wordsCode)
        return 0;
    memset(wordsCode, 0, sizeof(int) * wordsSize); //区别初始化为0,这不是必要步骤,不可省略

    //读取每个单词,并转化为morse码,再计算出单词Morse的对应的code值
    for (int i = 0; i < wordsSize; ++i)
    {
        char morse[100] = { 0 };
        for (int j = 0; words[i][j]; ++j)
        {
            int table_index = words[i][j] % 'a';
            strcat_s(morse,100, morseTable[table_index]);
        }
        wordsCode[i] = getWordCode(morse);
    }
    //调用qsort快速排序函数
    qsort(wordsCode, wordsSize, sizeof(int), compar);

    int count = getCount(wordsCode, wordsSize);


    free(wordsCode);

    return count;
}

1221. 分割平衡字符串

在一个「平衡字符串」中,‘L’ 和 ‘R’ 字符的数量是相同的。

给出一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。

返回可以通过分割得到的平衡字符串的最大数量。

示例 1:

输入:s = “RLRRLLRLRL” 输出:4 解释:s 可以分割为 “RL”, “RRLL”, “RL”, “RL”,
每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’。 示例 2:

输入:s = “RLLLLRRRLR” 输出:3 解释:s 可以分割为 “RL”, “LLLRRR”, “LR”,
每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’。 示例 3:

输入:s = “LLLLRRRR” 输出:1 解释:s 只能保持原样 “LLLLRRRR”.

提示:

1 <= s.length <= 1000 s[i] = ‘L’ 或 'R

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/split-a-string-in-balanced-strings
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:我的想法源于我学C语言结构体时碰到的一种叫做写时拷贝的技术,写时拷贝利用了一个引用计数机制,来记录结构体变化。同样我这里也引用这种机制,来记录遍历过程中的对称匹配情况。题解题能够找到的最优解也是这种思路,不过他们称为贪心算法,没学过贪心算法,但有兴趣学下。

int balancedStringSplit(const char* s) {
	//边界考虑
    if(!s)
        return 0;

    int res = 0;
    int count = 0;
    int i = 0;
    while (s[i])
    {
        s[i++] == 'R' ? ++count : --count;
        if (!count)
        {
            ++res;
        }
    }

    return res;
}

657. 机器人能否返回原点

在二维平面上,有一个机器人从原点 (0, 0) 开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0) 处结束。

移动顺序由字符串表示。字符 move[i] 表示其第 i 次移动。机器人的有效动作有 R(右),L(左),U(上)和
D(下)。如果机器人在完成所有动作后返回原点,则返回 true。否则,返回 false。

注意:机器人“面朝”的方向无关紧要。 “R” 将始终使机器人向右移动一次,“L” 将始终向左移动等。此外,假设每次移动机器人的移动幅度相同。

示例 1:

输入: “UD” 输出: true
解释:机器人向上移动一次,然后向下移动一次。所有动作都具有相同的幅度,因此它最终回到它开始的原点。因此,我们返回 true。 示例 2:

输入: “LL” 输出: false 解释:机器人向左移动两次。它最终位于原点的左侧,距原点有两次 “移动” 的距离。我们返回
false,因为它在移动结束时没有返回原点。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/robot-return-to-origin
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:二维平面中,定义x,y,读取字符串进行动态更新,最后判断

bool judgeCircle(char* moves) {
    if (!moves)
        return true;

    int x = 0, y = 0;
    int i = 0;
    while (moves[i])
    {
        switch (moves[i])
        {
        case 'R':   ++x;    break;
        case 'L':   --x;    break;
        case 'U':   ++y;    break;
        case 'D':   --y;    break;
        default:
            break;
        }
        ++i;
    }
    return x == 0 && x == y ? true : false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值