100天算法入门 - 每日三题 - Day13反转字符串反转字符串中的元音字母两个数组的交集

Posted 哪 吒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了100天算法入门 - 每日三题 - Day13反转字符串反转字符串中的元音字母两个数组的交集相关的知识,希望对你有一定的参考价值。

大连星海广场一角


算法是进阶架构师的基础,基础不牢,地动山摇,2021-8-14起开始刷题,目标100天,300道LeetCode算法题,分享是学习的最好方式,加油,嗨起来。

1、LeetCode 344.反转字符串

题目

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

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

你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

小编菜解

public static void reverseString(char[] s) {
    int n = s.length;
    int middle = 0;
    if (n%2 != 0){
        //如果是奇数,则第0个和n-1个交换,第1个和n-2个交换,一直交换到(n-1)/2-1个
        middle = (n-1)/2;
    }else{
        //如果是偶数,则第0个和n-1个交换,第1个和n-2个交换,一直交换到n/2-1个
        middle = n/2;
    }
    int left = 0;
    while (left < middle){
        char temp = s[left];
        s[left] = s[n-1-left];
        s[n-1-left] = temp;
        left++;
    }
}

越来越得心应手了,还得刷啊。 

大佬指点江山

public static void reverseString(char[] s) {
    int n = s.length;
    for (int left = 0,right = n-1;left<right;left++,right--){
        char temp = s[left];
        s[left] = s[right];
        s[right] = temp;
    }
}

虽然我也做出来了,但是代码量差的真多,而且思维没有达到这种高度。

2、LeetCode 345.反转字符串中的元音字母

题目

给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。

元音字母包括 'a''e''i''o''u',且可能以大小写两种形式出现。

小编菜解

public static String reverseVowels(String s) {
    List<Character> list = new ArrayList<Character>() {{
        add('a');
        add('e');
        add('i');
        add('o');
        add('u');
    }};
    char[] chars = s.toCharArray();
    int lg = s.length();
    int right = s.length();
    //遍历字符串前半段,如果是元音,则寻找右半段的最后一个元音,然后交换。
    //如果不是则不做处理。
    for (int left = 0; left < lg / 2; left++) {
        char e = 0;
        if (list.contains(chars[left])) {
            //寻找右半段的最后一个元音
            for (int j = right - 1; j >= 0; j--) {
                e = chars[j];
                if (list.contains(e)) {
                    right = j;
                    break;
                }
            }
            //交换最左元音和最右元音
            char temp = chars[left];
            chars[left] = e;
            chars[right] = temp;
        }
    }
    return new String(chars);
}

感觉list这块有点麻烦。

小编菜解改进版

public static String reverseVowels(String s) {
    String const_A_U = "aeiouAEIOU";
    char[] chars = s.toCharArray();
    int lg = s.length();
    int right = s.length();
    //遍历字符串前半段,如果是元音,则寻找右半段的最后一个元音,然后交换。
    //如果不是则不做处理。
    for (int left = 0; left < lg / 2; left++) {
        char e = 0;
        if (const_A_U.indexOf(chars[left])>=0) {
            //寻找右半段的最后一个元音
            for (int j = right - 1; j >= 0; j--) {
                e = chars[j];
                if (const_A_U.indexOf(e)>=0) {
                    right = j;
                    break;
                }
            }
            //交换最左元音和最右元音
            char temp = chars[left];
            chars[left] = e;
            chars[right] = temp;
        }
    }
    return new String(chars);
}

 虽然有点麻烦,但好赖思路清晰,感觉可以提交了,但是提示错误。Why?

大佬指点江山

public static String reverseVowels(String s) {
    String const_AE = "aeiouAEIOU";
    char[] chars = s.toCharArray();
    int lg = s.length();
    int left = 0;
    int right = lg - 1;
    //遍历字符串前半段,如果是元音,则寻找右半段的最后一个元音,然后交换。
    //如果不是则不做处理。
    while (left < right) {
        //如果不是元音
        while (left < lg && const_AE.indexOf(chars[left]) < 0) {
            ++left;
        }
        //如果不是元音
        while (right > 0 && const_AE.indexOf(chars[right]) < 0) {
            --right;
        }
        if (left < right) {
            char temp = chars[left];
            chars[left] = chars[right];
            chars[right] = temp;
            ++left;
            --right;
        }
    }
    return new String(chars);
}

大佬的思路和我的是一样的,但是利用双指针进行操作明显比我的前半段后半段,更加直观简洁。

3、LeetCode 349.两个数组的交集

题目

给定两个数组,编写一个函数来计算它们的交集。

小编菜解

public static int[] intersection(int[] nums1, int[] nums2) {
    Set<Integer> set = new HashSet<>();
    for (int i = 0; i < nums1.length; i++) {
        for (int j = 0; j < nums2.length; j++) {
            if (nums1[i] == nums2[j]){
                set.add(nums1[i]);
            }
        }
    }
    int[] arr = new int[set.size()];
    int i = 0;
    for (int s : set) {
        arr[i] = s;
        i++;
    }
    return arr;
}

虽然解决了问题,提交成功了,但是总感觉,菜的令人发指,不是很满意。 

小编菜解的时间复杂度是O(mn),也就是传统意义上的暴力算法,不建议采用。

思想及算法

如果使用哈希集合存储元素,则可以在 O(1)O(1) 的时间内判断一个元素是否在集合中,从而降低时间复杂度。

首先使用两个集合分别存储两个数组中的元素,然后遍历较小的集合,判断其中的每个元素是否在另一个集合中,如果元素也在另一个集合中,则将该元素添加到返回值。该方法的时间复杂度可以降低到 O(m+n)O(m+n)。

大佬指点江山

public static int[] intersection(int[] nums1, int[] nums2) {
    Set<Integer> set1 = new HashSet<>();
    Set<Integer> set2 = new HashSet<>();
    for (int i = 0; i < nums1.length; i++) {
        set1.add(nums1[i]);
    }

    for (int i = 0; i < nums2.length; i++) {
        set2.add(nums2[i]);
    }

    return getIntersection(set1, set2);
}

public static int[] getIntersection(Set<Integer> set1, Set<Integer> set2) {
    if (set1.size()>set2.size()){
        return getIntersection(set2,set1);
    }
    Set<Integer> set = new HashSet<>();
    for (Integer x : set1){
        if (set2.contains(x)){
            set.add(x);
        }
    }

    int[] ret = new int[set.size()];
    int i = 0;
    for (Integer x : set){
        ret[i++] = x;
    }
    return ret;
}

代码貌似更繁琐了,但重要的是这个思想,尽量避免多重for循环。

时间复杂度不一样,执行用时提升显著。

推荐阅读

【100天算法入门 - 每日三题 - Day12】Nim游戏、3的幂、4的幂

【100天算法入门 - 每日三题 - Day11】丢失的数字、移动零、单词规律

【100天算法入门 - 每日三题 - Day10】二叉树的所有路径、各位相加、丑数 

【100天算法入门 - 每日三题 - Day9】汇总区间、2的幂、有效的字母异位词

【100天算法入门 - 每日三题 - Day8】同构字符串、存在重复元素、翻转二叉树

【100天算法入门 - 每日三题 - Day7】验证回文串、只出现一次的数字、多数元素

【100天算法入门 - 每日三题 - Day6】对称二叉树、二叉树的最大深度、将有序数组转换为二叉搜索树

...

【100天算法入门 - 每日三题 - Day3】回文数、罗马数字转数字、最大公共前缀

【100天算法入门 - 每日三题 - Day2】二分查找、第一个错误的版本、搜索插入位置

【100天算法入门 - 每日三题 - Day1】二叉树的中序遍历、两数之和、整数反转

以上是关于100天算法入门 - 每日三题 - Day13反转字符串反转字符串中的元音字母两个数组的交集的主要内容,如果未能解决你的问题,请参考以下文章

100天算法入门 - 每日三题 - Day11丢失的数字移动零单词规律

100天算法入门 - 每日三题 - Day12Nim游戏3的幂4的幂

100天算法入门 - 每日三题 - Day15判断子序列最长回文数Fizz Buzz

100天算法入门 - 每日三题 - Day5最后一个单词的长度相同的树买卖股票的最佳时机

100天算法入门 - 每日三题 - Day16第三大的数字符串中的单词数排列硬币

100天算法入门 - 每日三题 - Day10二叉树的所有路径各位相加丑数