代码随想录算法训练营第八天| 344. 反转字符串、541. 反转字符串 II、替换字符串中的数字、55. 右旋字符串(第八期模拟笔试)

[LeetCode] 344. 反转字符串 文章说明

[LeetCode] 344. 反转字符串 文章说明

[LeetCode] 344. 反转字符串 视频说明

题目:

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:

输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]

示例 2:

输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

提示:

  • 1 <= s.length <= 105
  • s[i] 都是 ASCII 码表中的可打印字符

自己看到题目的第一想法:

    双指针, 一个指向头部, 一个指向尾巴. 将指针对应的字符串交换后, 分别向字符串的中心收缩. 直到两个指针重叠或者交叉.

看完代码随想录之后的想法:

    太简单了, 没有仔细看. 看到图片里的双指针, 应该和自己的想法是一样的.

class Solution {
    public void reverseString(char[] s) {
        char temp;
        for (int i = 0; i < s.length/2; i++) {
            temp = s[i];
            s[i] = s[s.length - 1 - i];
            s[s.length - 1 - i] = temp;
        }
    }
}

自己实现过程中遇到哪些困难:

    无

[LeetCode] 541. 反转字符串 II

[LeetCode] 541. 反转字符串 II 文章解释

[LeetCode] 541. 反转字符串 II 视频解释

题目:

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例 1:

输入:s = "abcdefg", k = 2
输出:"bacdfeg"

示例 2:

输入:s = "abcd", k = 2
输出:"bacd"

提示:

  • 1 <= s.length <= 104
  • s 仅由小写英文组成
  • 1 <= k <= 104

 自己看到题目的第一想法

    遍历字符串数组, 当前索引开始, 计算剩余的字符中, 是否有 k 个字符. 如果有则反转这 k 个字符, 否则反转剩下的全部字符.

看完代码随想录之后的想法

    写文章的时候和写算法差了两天, 有点忘记了. 这几天熬夜太多, 状态也变差了. 记不住自己当时的想法了, 好像文章没有太仔细的看.

class Solution {
    public String reverseStr(String s, int k) {
        char[] words = s.toCharArray();
        for (int i = 0; i < words.length; i += 2 * k) {
            if (i + k <=  words.length) {
                reverseStr(words, i, i + k - 1);
                continue;
            }
            reverseStr(words, i, words.length - 1);
        }
        return new String(words);
    }

    private void reverseStr(char[] words, int start, int end) {
        char temp;
        for (; start < end && start < words.length; start++, end--) {
            temp = words[start];
            words[start] = words[end];
            words[end] = temp;
        }
    }
}

替换数字

题目:

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。

例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。

对于输入字符串 "a5b",函数应该将其转换为 "anumberb"

输入:一个字符串 s,s 仅包含小写字母和数字字符。

输出:打印一个新的字符串,其中每个数字字符都被替换为了number

样例输入:a1b2c3

样例输出:anumberbnumbercnumber

数据范围:1 <= s.length < 10000。

自己看到题目的第一想法

    遍历数组, 计算一下替换完数字后, 所需要的数组的大小. 创建一个新的数组, 把数据从旧的数组, 从上往下复制到新的数组中.

看完代码随想录之后的想法

    今天看完解释之后发现, 自己第一反应的解法失去了题目本身的逻辑训练. 应该创建新的数组后, 将旧数组的内容复制到新数组中. 再进行算法的编写.

import java.util.Scanner;

// 这一题是比较简单的, 可以一次 ac
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String str = scanner.nextLine();
            if (str == null || str.length() == 0) {
                break;
            }
            char[] str2CharsOld = str.toCharArray();
            int newCharCount = 0;
            for (char strChar : str2CharsOld) {
                if (strChar >= '0' && strChar <= '9') {
                    newCharCount += 6;
                } else {
                    newCharCount += 1;
                }
            }
            char[] str2Chars = new char[newCharCount];
            for (int i = 0; i < str2CharsOld.length; i++) {
                str2Chars[i] = str2CharsOld[i];
            }
            int index = str2Chars.length - 1;
            for (int i = str2CharsOld.length - 1; i >= 0; i--) {
                if (str2CharsOld[i] >= '0' && str2CharsOld[i] <= '9') {
                    str2Chars[index--] = 'r';
                    str2Chars[index--] = 'e';
                    str2Chars[index--] = 'b';
                    str2Chars[index--] = 'm';
                    str2Chars[index--] = 'u';
                    str2Chars[index--] = 'n';
                } else {
                    str2Chars[index--] = str2CharsOld[i];
                }
            }
            System.out.println(new String(str2Chars));
        }
    }
}

自己实现过程中遇到哪些困难

    错误的理解了题目的意思, 导致偏题.

[LeetCode] 151. 反转字符串中的单词

[LeetCode] 151. 反转字符串中的单词 文章解释

[LeetCode] 151. 反转字符串中的单词 视频解释

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

示例 1:

输入:s = "the sky is blue"
输出:"blue is sky the"

示例 2:

输入:s = "  hello world  "
输出:"world hello"
解释:反转后的字符串中不能存在前导空格和尾随空格。

示例 3:

输入:s = "a good   example"
输出:"example good a"
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。

提示:

  • 1 <= s.length <= 104
  • s 包含英文大小写字母、数字和空格 ' '
  • s至少存在一个 单词

进阶:如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1) 额外空间复杂度的 原地 解法。

自己看到题目的第一想法

    先将每个单词反转一次, 再将整个字符串翻转过来. 我可真聪明(这里思路确实是对的, 也很快的能联想到, 算是一种进步吧).

// 这个是自己第一次的实现, 挺丑陋的
public class Solution {
    public String reverseWords(String s) {

        char[] wordChars = s.toCharArray();

        int wordStartIndex = -1;
        int slowIndex = 0;
        int fastIndex = 0;
        while (fastIndex < wordChars.length) {
            if (wordChars[fastIndex] != ' ') {
                wordChars[slowIndex] = wordChars[fastIndex];
                if (wordStartIndex == -1) {
                    wordStartIndex = slowIndex;
                } else if (fastIndex == wordChars.length - 1) {
                    reverseWords(wordChars, wordStartIndex, slowIndex);
                }
                slowIndex++;
            } else if (fastIndex > 0 && wordChars[fastIndex - 1] != ' ') {
                reverseWords(wordChars, wordStartIndex, slowIndex - 1);
                wordStartIndex = -1;
                wordChars[slowIndex++] = ' ';
            }
            fastIndex++;
        }

        if (slowIndex - 1 >= 0 && slowIndex - 1 < wordChars.length) {
            if (wordChars[slowIndex - 1] == ' ') {
                slowIndex--;
            }
        }
        reverseWords(wordChars, 0, slowIndex - 1);

        return new String(wordChars, 0, slowIndex);
    }

    private void reverseWords(char[] wordChars, int startIndex, int endIndex) {
        if (startIndex < 0 || startIndex >= wordChars.length
                || endIndex < 0 || endIndex >= wordChars.length
                || startIndex >= endIndex) {
            return;
        }
        char temp;
        for (int i = startIndex; i <= (startIndex + endIndex) / 2; i++) {
            temp = wordChars[i];
            wordChars[i] = wordChars[endIndex - (i - startIndex)];
            wordChars[endIndex - (i - startIndex)] = temp;
        }
    }
}

看完代码随想录之后的想法

    先将整个字符串翻转过来, 再反转每个单词. 同时要删除多余的空格. 保持 o(1) 空间复杂度. 当然java因为需要 String.toCharArray() 因此会额外损耗一些, 这是语言的约束.

public class Solution {
    public String reverseWords(String s) {
        char[] str2Chars = s.toCharArray();
        char temp;
        // 翻转字符串
        reverse(str2Chars, 0, str2Chars.length - 1);
        // 删除文字中间多余的空格
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < str2Chars.length; fastIndex++) {
            if (str2Chars[fastIndex] != ' ') {
                str2Chars[slowIndex++] = str2Chars[fastIndex];
            } else if (fastIndex > 0 && str2Chars[fastIndex - 1] != ' ') {
                str2Chars[slowIndex++] = ' ';
            }
        }
        if (slowIndex > 0 && str2Chars[slowIndex - 1] == ' ') {
            slowIndex--;
        }
        int leftIndex = -1;
        for (int i = 0; i < slowIndex; i++) {
            if (str2Chars[i] == ' ') {
                reverse(str2Chars, leftIndex + 1, i - 1);
                leftIndex = i;
            } else if (i == slowIndex - 1) {
                reverse(str2Chars, leftIndex + 1, i);
            }
        }
        return new String(str2Chars, 0, slowIndex);
    }
    private void reverse(char[] chars, int start, int end) {
        if (chars == null 
            || start < 0 || start >= chars.length
            || end < 0 || end >= chars.length
            || start >= end) {
                return;
        }
        char temp;
        for (;start < end; start++, end--) {
            temp = chars[start];
            chars[start] = chars[end];
            chars[end] = temp;
        }
    }
}

自己实现过程中遇到哪些困难:

    删除空格的时候, 使用 chars[i] == '\0', 这是错误的. 最后需要使用 new String(char[], int, int) 来生成目标字符串.

    因为需要删除空格, 因此一下子没想好字符串的结尾应该在哪. 陷入在快指针走到末尾时, 慢指针和快指针之间是有垃圾字符的. 但是我们只需要将慢指针看作结尾, 关注慢指针之间的字符就够了.

55. 右旋字符串(第八期模拟笔试)

题目描述

字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。 

例如,对于输入字符串 "abcdefg" 和整数 2,函数应该将其转换为 "fgabcde"。

输入描述

输入共包含两行,第一行为一个正整数 k,代表右旋转的位数。第二行为字符串 s,代表需要旋转的字符串。

输出描述

输出共一行,为进行了右旋转操作后的字符串。

输入示例
2
abcdefg
输出示例
fgabcde
提示信息

数据范围:
1 <= k < 10000,
1 <= s.length < 10000;

 自己看到题目的第一想法

    将字符串分为两部分, 将短的部分和长的部分做替换, 然后修改待替换字符的索引, 直到替换完成.

// 也算是完成了吧...
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int count = scanner.nextInt();
            String word = scanner.nextLine();
            char[] wordChars = word.toCharArray();

            int saveStartIndex;
            int saveEndIndex;
    
            int moveStartIndex;
            int moveEndIndex;
    
            char temp;
    
            if (wordChars.length/2 >= count) {
                // 头部长, 从底部移动到头部
                saveStartIndex = 0;
                saveEndIndex = wordChars.length - count - 1;
                moveStartIndex = saveEndIndex + 1;
                moveEndIndex = wordChars.length - 1;
    
                while (saveStartIndex <= saveEndIndex) {
                    for (int i = moveStartIndex; i <= moveEndIndex; i++) {
                        temp = wordChars[i];
                        wordChars[i] = wordChars[saveStartIndex];
                        wordChars[saveStartIndex] = temp;
                        saveStartIndex++;
                    }
                }
            } else {
                // 头部短, 从头部往底部移
                moveStartIndex = 0;
                moveEndIndex = wordChars.length - count - 1;
                saveStartIndex = moveEndIndex + 1;
                saveEndIndex = wordChars.length - 1;
    
                while (saveStartIndex <= saveEndIndex) {
                    for (int i = moveStartIndex; i <= moveEndIndex; i++) {
                        temp = wordChars[saveStartIndex];
                        wordChars[saveStartIndex] = wordChars[i];
                        wordChars[i] = temp;
                        if (saveStartIndex + 1 <= saveEndIndex) {
                            saveStartIndex++;
                        } else if (i + 1 == saveEndIndex) {
                            saveStartIndex++;
                        }
                    }
                    moveStartIndex = moveEndIndex + 1;
                    moveEndIndex = moveStartIndex + (wordChars.length - count - 1);
                }
    
            }
    
            String result = new String(wordChars);
            System.out.println(result);
        }
    }
}

看完代码随想录之后的想法

    真没想到T_T 可以那么简单

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int count = Integer.parseInt(scanner.nextLine().trim());
            String word = scanner.nextLine();

            if (word == null || count > word.length()) {
                return;
            }
            char[] wordChars = word.toCharArray();
            reverseChars(wordChars, 0, wordChars.length - 1);
            reverseChars(wordChars, 0, count - 1);
            reverseChars(wordChars, count, wordChars.length - 1);
            System.out.println(new String(wordChars));
        }
    }
    
    // 翻转字符串
    private static void reverseChars(char[] wordChars, int start, int end) {
        char temp;
        while (start < end) {
            temp = wordChars[start];
            wordChars[start] = wordChars[end];
            wordChars[end] = temp;
            start++;// 一开始这里没有写, 编译器一直说数组越界, 给我带偏了T_T
            end--;
        }
    }
}

自己实现过程中遇到哪些困难

    代码有逻辑问题, 编译器的报错提示把我带偏了. 对比了一下文章里的实现, 才发现哪里有问题. 还有是 Scanner.nextLine() 会导致输入的数字字符串中带有空格, 会解析异常. 还有就是, 代码模板里的逻辑不是很好用.

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值