LeetCode5377. 将二进制表示减到 1 的步骤数
文章目录
- LeetCode5377. 将二进制表示减到 1 的步骤数
- 题目描述
- 解题思路
- AC代码
题目描述
给你一个以二进制形式表示的数字 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%的参赛用户都成功通过了此题。
一看到题目就给人一种熟悉的感觉,似乎以前见过这个题。周赛结束后我去百度上搜索了这个题,各大 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。