leetcode-将二进制表示减到 1 的步骤数

 题目是LeetCode第183场周赛的第二题,链接:将二进制表示减到 1 的步骤数。具体描述为:给你一个以二进制形式表示的数字 s 。请你返回按下述规则将其减少到 1 所需要的步骤数:如果当前数字为偶数,则将其除以 2 。如果当前数字为奇数,则将其加上 1 。题目保证你总是可以按上述规则将测试用例变为 1 。

  • 1 <= s.length <= 500
  • s 由字符 ‘0’ 或 ‘1’ 组成。
  • s[0] == ‘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

 一种简单的思路就是直接模仿二进制操作,用一个left和一个right记录我们所操作的二进制数的位置为left到right(当然这里的left总是0可以去掉)。除以2相当于数右移一位,等价于right-1。加1的话需要模仿二进制加法,遇到111...111的特殊情况可能会导致left左移而越界,好在这种情况下已经可以知道还需要多少次操作便可以得到需要的1(因为+1后就是1000...000的格式,只需要不断除以2,需要的次数就是0的个数)。时间复杂度为 O ( n ) O(n) ,空间复杂度为 O ( n ) O(n)

 JAVA版代码如下:

class Solution {
    public int numSteps(String s) {
        char[] chars = s.toCharArray();
        int left = 0;
        int right = s.length() - 1;
        int count = 0;
        while (left < right) {
            if (chars[right] == '0') {
                ++count;
                --right;
            }
            else {
                // 奇数的时候必定是先+1(所以有进位)变为偶数再除以2,两步一块做了
                count += 2;
                boolean carry = true;
                --right;
                for (int i = right; i >= left; --i) {
                    if (carry) {
                        if (chars[i] == '1') {
                            chars[i] = '0';
                            if (i == left) {
                                // 第一位也产生进位,说明这个数是111...111的格式
                                // +1后是1000...000,可以知道接下来还需要多少次除以2的操作得到1
                                return count + right - left + 1;
                            }
                        }
                        else {
                            chars[i] = '1';
                            carry = false;
                        }
                    }
                    else {
                        break;
                    }
                }
            }
        }
        return count;
    }
}

 提交结果如下:


 上面的代码还是有点繁琐,可以稍作改变写成下面的更简洁的:

class Solution {
    public int numSteps(String s) {
        int count = 0;
        int i = s.length() - 1;
        char[] chars = s.toCharArray();
        while (i > 0) {
            if (chars[i] == '0') {
                ++count;
                --i;
            }
            else {
                // 奇数+1之后会产生进位,需要考虑前面有多少个连续的1
                ++count;
                // 有多少个连续的1就会在+1之后产生多少个0,也就需要多少次除以2
                while (i > 0 && chars[i] == '1') {
                    ++count;
                    --i;
                }
                if (i > 0) {
                    chars[i] = '1';
                }
                else {
                    // 一直到首位都是1的话已经可以得到结果了
                    return count + 1;
                }
            }
        }
        return count;
    }
}

 提交结果如下:


 另一种也蛮简洁的写法(空间复杂度为 O ( 1 ) O(1) )如下:

class Solution {
    public int numSteps(String s) {
        int count = 0;
        boolean carry = false;
        for (int i = s.length() - 1; i >= 0; --i) {
            if (!carry && i == 0) {
                // 对应于100...000这种情况,避免进入后面的+1再除以2
                break;
            }
            if ((carry && s.charAt(i) == '0') || (!carry && s.charAt(i) == '1')) {
                // 有进位且当前位为0或没进位且当前位为1都会导致当前位实际为1,需要两步:+1然后除以2
                ++count;
                carry = true;
            }
            // 除以2的那一步
            ++count;
        }
        return count;
    }
}

 提交结果如下:


 Python版代码如下:

class Solution:
    def minSubsequence(self, nums: List[int]) -> List[int]:
        count = [0 for _ in range(100)]
        totalSum = 0
        for n in nums:
            totalSum += n
            count[n - 1] += 1
        result = []
        cumSum = 0
        for i in range(99, -1, -1):
            for j in range(count[i]):
                result.append(i + 1)
                cumSum += i + 1
                if cumSum > totalSum - cumSum:
                    return result
        return result

 提交结果如下:


发布了68 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/JR_Chan/article/details/105415051
今日推荐