JAVA入门算法题(八)

版权声明:很高兴认识你,我叫邵龙飞 原创文章,转载请注明 https://blog.csdn.net/qq_37482202/article/details/85203291

有志者自有千计万计,无志者只感千难万难。

1.报数序列

/**
     * 报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
     * 1.     1
     * 2.     11
     * 3.     21
     * 4.     1211
     * 5.     111221
     * 1 被读作  "one 1"  ("一个一") , 即 11。
     * 11 被读作 "two 1s" ("两个一"), 即 21。
     * 21 被读作 "one 2",  "one 1" ("一个二" ,  "一个一") , 即 1211。
     * 给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
     * 注意:整数顺序将表示为一个字符串。
     *
     * 示例 1:
     * 输入: 1
     * 输出: "1"
     *
     * 示例 2:
     * 输入: 4
     * 输出: "1211"
     */

读完题你可能有点晕,感觉这道题就想脑筋急转弯一样,不知道要求什么,其实这道题只是读起来绕口,算起来很简单,给你点提示,它的前10项是这样的

The following are the terms from n=1 to n=10 of the count-and-say sequence:

 1.     1
 2.     11
 3.     21
 4.     1211
 5.     111221 
 6.     312211
 7.     13112221
 8.     1113213211
 9.     31131211131221
10.     13211311123113112211

它的意思就是读出来上一组数字,第一组数字是1,第二组就是“一个一“——11,第三组就是“两个1”——21,第四组是“一个二,一个一”——121,1,第五组就是“一个一,一个二,两个一”——111221,整道题就想一个翻译器一样,解决这样的问题最容易的就是递归。

采用递归和快慢指针的方法计数,并对最后的一个数字做特殊处理

private static String method1(int n){
        if (n==1) return "1";
        String deel=method1(n-1);
        String result="";
        char aim=deel.charAt(0);
        int num=0;
        for (int i=0;i<deel.length();i++){
            if (deel.charAt(i)!=aim){
                result+=num+""+aim;
                num=0;
                aim=deel.charAt(i);
            }
            num++;
            if (i==deel.length()-1){
                result+=num+""+aim;
            }
        }
        return result;
    }

也可以递归加双层for循环计数

private static String method2(int n){
        if (n == 1) {
            return "1";
        }
        String input = method2(n - 1);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            char currDigit = input.charAt(i);
            int currTimes = 1;
            for (int j = i + 1; j < input.length(); j++) {
                if (currDigit == input.charAt(j)) {
                    currTimes++;
                } else {
                    break;
                }
            }
            i += currTimes - 1;
            sb.append(currTimes).append(currDigit);
        }
        return sb.toString();
    }

2.压缩数组

/**
     *给定一组字符,使用原地算法将其压缩。
     * 压缩后的长度必须始终小于或等于原数组长度。
     * 数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。
     * 在完成原地修改输入数组后,返回数组的新长度。
     *
     * 示例 1:
     * 输入:
     * ["a","a","b","b","c","c","c"]
     * 输出:
     * 返回6,输入数组的前6个字符应该是:["a","2","b","2","c","3"]
     * 说明:
     * "aa"被"a2"替代。"bb"被"b2"替代。"ccc"被"c3"替代。
     *
     *
     *1.  所有字符都有一个ASCII值在[35, 126]区间内。
     *2.  1 <= len(chars) <= 1000。
     */

首先可以确定的是这道题还是要用到快慢指针,但是这里需要注意的一点便是有的字母出现的次数超过9次,这样的话就需要把该数字写到两个地方可以使用String来存取数字。

public static int method2(char[] chars) {
        if (chars.length==1) return 1;
        int slow=0;
        char old=chars[0];
        int number=0;

        for (int i=0;i<=chars.length;i++){
            if (i==chars.length||old!=chars[i]){
                if (number==1){
                    if (i==chars.length){
                        chars[slow]=old;
                        slow++;
                        continue;
                    }
                    chars[slow]=old;
                    old=chars[i];
                    slow++;
                    continue;
                }
                String a=number+"";
                chars[slow]=old;
                slow++;
                for(int j=0;j<a.length();j++){
                    chars[slow]=a.charAt(j);
                    slow++;
                }
                if (i!=chars.length){
                    old=chars[i];
                    number=1;
                }
            }else {
                number++;
            }
        }
        return slow;
    }

上面这种写法既要考虑开头又要考虑结尾,最好还要写出现的次数,显得又臭又长,我们可以变换思维,不断比较下一位是否相同再做判断。

public static int method1(char[] chars) {
        if(chars.length == 0) return 0;
        int mark = 0;
        int write = 0;
        for(int i = 0; i < chars.length; i++){
            if(i + 1 == chars.length || chars[i] != chars[i+1]){
                chars[write] = chars[mark];
                write++;
                if(mark < i){
                    for(char a : (""+(i-mark+1)).toCharArray())
                        chars[write++] = a;
                }
                mark = i + 1;
            }
        }
        return write;
    }

3.最大子序和

/**
     *给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
     *
     * 示例:
     * 输入: [-2,1,-3,4,-1,2,1,-5,4],
     * 输出: 6
     * 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
     */

最笨的方法便是遍历每一种可能,然后求出最大值。

机智的办法便是首先定义最大值为数组第一位,遍历一遍数组,不断地求和,当总和小于0的时候重新计数,最后比较数组和和最大值的大小,返回最大。

public static int method1(int[] nums) {
        int max = nums[0];
        int sum = nums[0];
        for(int i = 1; i < nums.length; i++){
            if(sum < 0){
                sum = nums[i];
            } else{
                sum += nums[i];
            }
            if(sum > max){
                max = sum;
            }
        }
        return max;
    }

换一种优雅的写法

public static int method2(int[] nums){
        int res = nums[0];
        int sum = 0;
        for (int num : nums) {
            if (sum > 0)
                sum += num;
            else
                sum = num;
            res = Math.max(res, sum);
        }
        return res;
    }

4.最后单词的长度

/**
     *给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度。
     * 如果不存在最后一个单词,请返回 0 。
     * 说明:一个单词是指由字母组成,但不包含任何空格的字符串。
     */

看到这道题的第一时间想到的就是正则表达式,这也是最容易实现的方式

public static int method1(String s) {
        Pattern pattern=Pattern.compile("\\b[a-zA-Z]+\\b");
        Matcher matcher=pattern.matcher(s);
        int number=0;
        while (matcher.find()){
            number=matcher.group().length();
        }
        return number;
    }

如果抛去正则表达式,因为找的是最后一个单词的长度,所以可以采用从后往前找单词的方法,找到第一个字母开始计数,直到找到空格为止

public static int method1(String s) {
        Pattern pattern=Pattern.compile("\\b[a-zA-Z]+\\b");
        Matcher matcher=pattern.matcher(s);
        int number=0;
        while (matcher.find()){
            number=matcher.group().length();
        }
        return number;
    }

还有一种更为简洁的实现方式,String类提供了trim()方法,只要找到去掉最后空格的长度和倒数第一个空格的位置就ok了

public static int method3(String s) {
        return s.trim().length()-s.trim().lastIndexOf(" ")-1;
    }

猜你喜欢

转载自blog.csdn.net/qq_37482202/article/details/85203291
今日推荐