简单题总结1 | 豆包MarsCode AI刷题

62 阅读7分钟

一、找单独的数

题目概述:

在一组只有一个数字没重复的数据中找出那个只出现一次的数,如在1, 1, 2, 2, 3, 3, 4, 5, 5中该数为4.

解题思路描述

这个题最简单快捷的方法就是用异或来遍历这组数据,一次就可以找到该数。但这个方法比较巧妙,如果一开始没有这种思维,老老实实的去一个个数字的找,也可以找到答案,但是这样不仅代码更多,时间复杂度也更高。

解题代码

public class Main {
    public static int solution(int[] cards) {
        // Edit your code here
        int result = 0;
        for(int i=0;i<cards.length;i++){
            result ^= cards[i];
        }
        return result;
    }

    public static void main(String[] args) {
        // Add your test cases here 
        System.out.println(solution(new int[]{1, 1, 2, 2, 3, 3, 4, 5, 5}) == 4);
        System.out.println(solution(new int[]{0, 1, 0, 1, 2}) == 2);
    }
}

总结

这个问题是一个比较经典的算法题,也比较简单,将这个题目扩大就是找一组数据中的唯一出现奇数次的数。主要是其中的异或思想比较典型,还有一些关于异或的经典问题有,用异或来交换两个变量的值,位运算等等。

二、数字字符串格式化

题目描述

小M在工作时遇到了一个问题,他需要将用户输入的不带千分位逗号的数字字符串转换为带千分位逗号的格式,并且保留小数部分。小M还发现,有时候输入的数字字符串前面会有无用的 0,这些也需要精简掉。请你帮助小M编写程序,完成这个任务。

解题思路

解这个题目的关键点在于如何确定千分位逗号的位置,不过它有个准备操作,要先确定有效整数部分的位置,也就是从非零整数位一直到小数点前的位置。准备好之后就可以加千分位逗号了,这里采取的方式是先计算出需要几个千分位号,再利用这个千分位号来确定要加进去的相对位置,进而得出绝对位置。采取的策略是一边遍历一边判断插入。最后别忘了加上小数部分。

解题代码

public class Main {
    public static String solution(String s) {
        // write code here
        StringBuffer result = new StringBuffer();
        int start = 0;
        int end = 0;
        int num = 0;
        int i = 0;

        //找到整数部分的第一个有效数字
        while(start < s.length() && s.charAt(start) == '0' && s.charAt(start) != '.'){
            start++;
        }
        //找到小数点所在位置
        //也可以找到小数点前一位
        while(end < s.length() && s.charAt(end) != '.'){
            end++;
        }
        
        if(start == s.length() && end == s.length()){
            //该数字为0就直接返回
            return "0";
        }else if(start == end){
            //只有小数就直接返回这个小数
            return "0" + s.substring(start);
        }
        //System.out.println(end - start);
        //计算会有几个千分位逗号
        num = (end - start) / 3;
        i = start;
        while(i < end){
            result.append(s.charAt(i));
            //System.out.println(end-start-1-num*3);

            //end-start-1-num*3计算的是在整个有效整数部分中第num个千分位号所占的相对位置
            //因为这个相对位置是相对于start的所以最后的结果要加上start
            //还有最后一个千分位号不加
            if(i==start+(end-start-1-num*3) && i != end - 1){
                result.append(',');
                num--;
            }
            //如果有效整数是3的倍数那么第一个位置也不需要
            //比如987,654,321不需要在9前加千分位号
            if(end-start-1-num*3 < 0){
                num--;
            }
            i++;
        }
        
        result.append(s.substring(end));       
        return result.toString();
    }

    public static void main(String[] args) {
        System.out.println(solution("1294512.12412").equals("1,294,512.12412"));
        System.out.println(solution("0000123456789.99").equals("123,456,789.99"));
        System.out.println(solution("987654321").equals("987,654,321"));
        //System.out.println(solution("1294512.12412"));
        System.out.println(solution("0000123456789.99"));
    }
}

总结

这个题目一开始想的太简单了,在插入的时候就想着三个一组从前往后或者从后往前的出,但是后面发现三个一组从前往后千分号的顺序是乱的,不符合千分号的定义;而从后往前遍历数字又是倒过来的,然后才意识到要先确定千分号的具体位置,判断是不是该位置才能实现插入。当然前面的操作也可行,只需要从后往前一直往第一个位置插入就行,这里由于是我一开始写的代码,就按照这个思路做了。另外代码中可能还有很多不完美的地方,解题还不够干脆利落,希望这点可以在之后的刷题进程中得到锻炼。

三、数字分组求偶数和

题目描述

小M面对一组从 1 到 9 的数字,这些数字被分成多个小组,并从每个小组中选择一个数字组成一个新的数。目标是使得这个新数的各位数字之和为偶数。任务是计算出有多少种不同的分组和选择方法可以达到这一目标。

  • numbers: 一个由多个整数字符串组成的列表,每个字符串可以视为一个数字组。小M需要从每个数字组中选择一个数字。

例如对于[123, 456, 789],14个符合条件的数为:147 149 158 167 169 248 257 259 268 347 349 358 367 369

解题思路

很明显,解这个题目需要用到排列组合的知识,可以将每个数字看成一个箱子,箱子里由该数字按十进制拆分得到,每个箱子里选一个数字构成新的数,选择其中是偶数的。也可以将这个题目看成是选子集的过程。而构造集合并选取特定子集的经典算法就是回溯。即通过尝试所有可能的解决方案来找到所有解。

解题代码

import java.util.List;
import java.util.ArrayList;

public class Main {
    public static int recurision(int last,List<Integer> numbers){
        int result = 0;
        int tmp = numbers.get(0);
        //当只剩最后一个数字之后可以直接判断生成的数字是不是偶数
        if(numbers.size() == 1){
            while(tmp > 0){
                if((tmp%10+last)%2 == 0){
                    //System.out.println(tmp%10+last);
                    result++;
                }
                tmp /= 10;
            }
            return result;
        }
        numbers.remove(0);
        
        while(tmp > 0){
            int k = tmp%10;
            last += k;
            //System.out.println(k);
            List<Integer> tmpList = new ArrayList<>(numbers);
            result += recurision(last,tmpList);
            tmp /= 10;
            last -= k;
        }

        return result;
    }
    public static int solution(int[] numbers) {
        // Please write your code here
        int result = 0;
        int len = numbers.length;
        int tmp = numbers[0];
        List<Integer> coList = new ArrayList<>();
        if(len == 1){
            while(tmp > 0){
                if(tmp%10%2 == 0){
                    result++;;
                }
                tmp /= 10;
            }
            return result;
        }

        //生成一个数据的复制版本便于操作后恢复
        for(int i=1;i<numbers.length;i++){
            coList.add(numbers[i]);
        }
        tmp = numbers[0];
        //因为这里递归操作选择的是删除,所以为了使每次递归之后数据能恢复,这里
        //以第一个数字每一位进入回溯
        while(tmp > 0){
            List<Integer> tmpList = new ArrayList<>(coList);
            //System.out.println(tmp%10);
            result += recurision(tmp%10,tmpList);
            tmp /= 10;

        }
        return result;
    }

    public static void main(String[] args) {
        // You can add more test cases here
        System.out.println(solution(new int[]{123, 456, 789}) == 14);
        System.out.println(solution(new int[]{123456789}) == 4);
        System.out.println(solution(new int[]{14329, 7568}) == 10);
        //System.out.println(solution(new int[]{123, 456, 789}));
    }
}

总结

该题的代码主要流程是遍历每个数字的每一位,并递归地将这些数字与其他数字的各位进行组合;判断组合的和是否为偶数,如果是偶数,则将其计入最终结果;回溯法:在递归中,回溯到上一层时撤回当前数字的贡献,保证每一层的递归操作是独立的。要注意的一点就是,因为这题我选择递归的截止条件是数据中只剩一个数字,所以会有删除操作,因此每次递归的时候都需要对之前的数据备份,否则会丢失掉。当然,该题可能存在很多很好的解题方法和代码,这里只是说一下我的解题思路。

如果代码有任何不正确的,或者不完善的地方,希望能得到建议,谢谢~.~