LeetCode5377. 将二进制表示减到1的步骤数

LeetCode5377. 将二进制表示减到 1 的步骤数

题目描述

给你一个以二进制形式表示的数字 s 。请你返回按下述规则将其减少到 1 所需要的步骤数:

  • 如果当前数字为偶数,则将其除以 2 。
  • 如果当前数字为奇数,则将其加上 1 。

题目保证你总是可以按上述规则将测试用例变为 1 。

示例 1:

输入:s = “1101”
输出:6
解释:“1101” 表示十进制数 13 。
Step 1) 13 是奇数,加 1 得到 14
Step 2) 14 是偶数,除 2 得到 7
Step 3) 7 是奇数,加 1 得到 8
Step 4) 8 是偶数,除 2 得到 4
Step 5) 4 是偶数,除 2 得到 2
Step 6) 2 是偶数,除 2 得到 1

示例 2:

输入:s = “10”
输出:1
解释:“10” 表示十进制数 2 。
Step 1) 2 是偶数,除 2 得到 1

示例 3:

输入:s = “1”
输出:0

提示:

  • 1 <= s.length <= 500
  • s 由字符 ‘0’ 或 ‘1’ 组成。
  • s[0] == ‘1’

解题思路

此题来源于 LeetCode第183场周赛,题目难度是 Medium,大约80%的参赛用户都成功通过了此题。
le1

一看到题目就给人一种熟悉的感觉,似乎以前见过这个题。周赛结束后我去百度上搜索了这个题,各大 OJ里是有这个题的。这个题的来源是数学的角谷定理(原来叫角谷猜想,后来已经被成功证明了)。

所谓角谷猜想,是指对于任意一个正整数,如果是奇数,则乘3加1,如果是偶数,则除以2,得到的结果再按照上述规则重复处理,最终总能够得到1。例如,假定初始整数为5,计算过程分别为16、8、4、2、1。

这里 LeetCode官方对题目进行了一些更改,题目原本是整数的运算,这里改成了二进制+字符串的形式。同时将难度调低了一些,奇数时仅进行加1运算。

看到题目第一个想到的就是二进制转为十进制,然后进行运算。瞅了一眼题目提示,s.length<=500,转换出来的数据太大了,直接放弃了这一想法。

然后想到的是针对字符串进行按位处理。对于偶数来说,直接舍去后面的‘0’字符即可;对于奇数来说,加1就涉及到进位的问题,如果每一位都是1则全部要进位,处理起来很麻烦。

仔细思考了一会后觉得可以用按位翻转的思想进行模拟。最后一位是1,加1之后就变成0,同时进位;如果倒数第二位也是1,加上进位的1也变成0,再进位。这就相当于将每一位上的1翻转为0,层层向上翻转,遇到第一个0将其翻转为1即完成了整个进位过程。

对于用例“11111”来说,全部翻转为0之后前面应该还有个1才能保证值不变,因此我想到在字符串前面添加一个‘0’用来解决这种情况,“011111”翻转之后变成“100000”,偶数处理一步一步舍去“0”,剩下为“1”,这样保证了一定有一个“0”来完成进位过程。

这里有一个特殊情况:“10”。对于“10”来说舍去“0”已经变成“1”了,只需要处理一次就行。我的方法在前面添加“0”之后变成“010”,偶数舍去最后一位“0”后还剩“01”,这个时候对“01”进行特判输出即可。

因此输出条件有两个:

  • 字符串处理后仅为“1”
  • 字符串处理后为“01”

AC代码

代码采用 Java语言进行书写。

这里采用 StringBuilder而不用String是为了节省内存空间,因为对 String的操作是每次新生成一个 String对象,然后将引用更改到这个对象上。StringBuilder是只创建一个对象,所有的操作都针对的是对象本身。

这里对 “1” 进行特判主要是省内存,当然也可以不用特判,因为 “1” 最终也会转换为 “01” 进行判断的。

class Solution {
    public int numSteps(String s) {
        int len=s.length();
        if(len==1){
            return 0;
        }
        else
        {
            int num=0;
            StringBuilder str=new StringBuilder("0");
            str.append(s);
            while(true)
            {
                len=str.length();
                if(len==1||(len==2&&str.charAt(0)=='0'&&str.charAt(1)=='1')){
                    break;
                }
                else{
                    if(str.charAt(len-1)=='1')
                    {
                        for(int i=len-1;i>=0;i--)
                        {
                            if(str.charAt(i)=='0')
                            {
                                str.setCharAt(i,'1');
                                num++;
                                break;
                            }
                            else
                            {
                                str.setCharAt(i,'0');
                            }
                        }
                    }
                    else
                    {
                        str.deleteCharAt(len-1);
                        num++;
                    }
                }
            }
            return num;
        }
    }
}

本来我是想用 StringBuilder的 equals方法直接比较相等的,结果运行起来总是报错,百度后才发现原来 StringBuilder是没有 equals方法的。

因为这次的相等只判断两个数位,所以就直接写了一个朴素版的判断。

len == 2 && str.charAt(0) == ‘0’ && str.charAt(1) == ‘1’

周赛结束后马上提交了测评看看数据,很 nice。
le2

发布了61 篇原创文章 · 获赞 25 · 访问量 7171

猜你喜欢

转载自blog.csdn.net/qq_42582489/article/details/105325407
今日推荐