每日一题补题记录11

3.2

564. 寻找最近的回文数

给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身)。如果不止一个,返回较小的那个。

“最近的”定义为两个整数差的绝对值最小。

我们显然不能采取枚举法,一个可以大致猜测的方法是,将原争取取前一半然后反转,这样可以得到一个很接近的回文数,比如114514,我们取半反转就是114411,但是要求“最近”的要求很严苛,所以还要进行更进一步的分析,假设前半部分为abcde,我们将abcde\abcde-1\abcde+1三个数字依次展开得到回文数再选出最近的即可。

class Solution {
    public String nearestPalindromic(String n) {
        int len=n.length();
        long value=Long.parseLong(n),ans=-1;
        List<Long>list=get(n);
        for(long num:list){
            System.out.println(num);
            if(num!=value){
                if(ans==-1||Math.abs(num-value)<Math.abs(ans-value)||
                (Math.abs(num-value)<Math.abs(ans-value)&&num<ans)){
                    ans=num;
                }
            }
        }
        return String.valueOf(ans);
    }
    //前半部分为abc,但是我们要考虑abc/abc+1/abc-1再反转
    List<Long> get(String n){
        int len=n.length();
        List<Long>ans=new ArrayList<>();
        if(len==1){
            long num=Long.parseLong(n);
            ans.add(num-1);
            ans.add(num);
            ans.add(num+1);
            return ans;
        }
        int mid=len/2;   
        for(int i=0;i<3;i++){
            StringBuffer sb=new StringBuffer();
            for(int j=0;j<mid-1;j++){
                sb.append(n.charAt(j));
            }
            //偶数
            if(len%2==0){
                sb.append((char)(n.charAt(mid-1)+i-1));
            }else{
                sb.append(n.charAt(mid-1));
                sb.append((char)(n.charAt(mid)+i-1));
            }
            for(int j=mid-1;j>=0;j--){
                sb.append(sb.charAt(j));
            }
            ans.add(Long.parseLong(sb.toString()));
        }
        return ans;
    }
}

但是没有通过,原因是什么呢,可以看到,碰到10,我们是考虑不到9这种回文串的,因此我们要考虑两种边界情况,比如一个五位数,不管是多少,其两个边界回文数是9999和100001,因此我们实际上要考虑五种数字。

但是后来又BUG了无数次……最终还是CV了别的大佬的代码,不知道自己为什么老是过不了,可能是字符串太变态了吧

class Solution {
    public String nearestPalindromic(String n) {
        // 五种情况:
        // 1. 把前一半对称到后一半,12345->12321
        // 2. 把前一半加一对称到后一半,12321->12421
        // 3. 把前一半减一对称到后一半,12321->12221
        // 4. 类似于9999,最近的是10001
        // 5. 类似于10001,最近的是9999
        // 上述五种情况取不等于原数且绝对值最小的

        long origin = Long.valueOf(n);
        int len = n.length();
        long half = Long.valueOf(n.substring(0, (len + 1) / 2));

        List<Long> list = new ArrayList<>();
        list.add(mirror(half, len));
        list.add(mirror(half + 1, len));
        list.add(mirror(half - 1, len));
        list.add(upper(len));
        list.add(lower(len));

        long ans = 0;
        long min = Long.MAX_VALUE;
        for (Long x : list) {
            long abs = Math.abs(x - origin);
            if (x != origin && (abs < min || (abs == min && x < ans))) {
                min = abs;
                ans = x;
            }
        }
        return String.valueOf(ans);
    }

    private long mirror(long half, int len) {
        // 奇数位:12345->12321
        // 偶数位: 1234->1221
        long x = half;
        long ans = half;
        if ((len & 1) == 1) {
            x /= 10;
        }

        while (x != 0) {
            ans = ans * 10 + x % 10;
            x /= 10;
        }

        return ans;
    }

    private long upper(int len) {
        // 9999 -> 10001
        long ans = 1;
        while (len-- > 0) {
            ans *= 10;
        }
        return ans + 1;
    }

    private long lower(int len) {
        // 10001 -> 9999
        long ans = 0;
        while (--len > 0) {
            ans = ans * 10 + 9;
        }
        return ans;
    }
}

3.3

258. 各位相加

这个题目首先最简单的肯定是模拟,最后长度固定在1即可,其次可以用数学方法

这张图用人话说,就是100x+10y+z和x+y+z模9同余,直到最后的一个x+y+z<=9,因为整个变化过程都模9同余,那么我们可以直接用num来计算这个数根x+y+z<=9,如果num不是9的倍数直接返回num%9即可,如果num是9的倍数那么num%9==0,显然要单独处理,如果num==0就返回0不然返回9

class Solution {
    public int addDigits(int num) {
        return num==0?num==0?0:9:num%9;
    }
}

3.4

2104. 子数组范围和

给你一个整数数组 nums 。nums 中,子数组的 范围 是子数组中最大元素和最小元素的差值。

返回 nums 中 所有 子数组范围的 和 。

子数组是数组中一个连续 非空 的元素序列。

我们可以按照左右边界来遍历所有子数组,将每一个范围加入答案即可

class Solution {
    public long subArrayRanges(int[] nums) {
        int n=nums.length;
        long ans=0;
        //相同左边界的子数组
        for(int i=0;i<n;i++){
            //每一个新开始,都没有过去的数值参考,因此要初始化max和min
            int min=nums[i];
            int max=nums[i];
            //右边界
            //右边界变化,更新min和max
            for(int j=i+1;j<n;j++){
                min=Math.min(min,nums[j]);
                max=Math.max(max,nums[j]);
                ans+=max-min;
            }
        }
        return ans;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值