Hard级别的新题:给定非负整数n,你可以使用两种操作, 把它变为0。两种操作是:
(1)变换最低二进制位。
(2)变换非最低二进制位,比它更低的位必须是1000000....。
求最少操作次数。
数据范围0<=n<=1000000000。
例如输入n = 0,返回0。
再如输入n = 3,返回2。因为要11->01->10
分析:比较难的题,其实是格雷码,但要仔细分析……用几个例子试一下2的幂 (用二进制表示)
1->0 1步
10->11->01->00 3步
100->101->111->110->010->011->001->000 7步
从2 ^ m变为0,需要2 ^ (m + 1) - 1步——即上面每条链包含2 ^ (m + 1)个数。
来看一下如何构造:
按最高位分成两段 ,最高位为1是前半段,低位是上一条链倒置, 最高位为0的是后半段, 低位完全是上一条链。
例如100开始的链
前半段是1(00)->1(01)->1(11)->1(10)
括号里的部分恰好是上一条链10->11->01->00倒过来 (其实从x变成0和从0变成x步数一样)。
后半段是0(10)->0(11)->0(01)->0(00)
括号里的部分正好就是上一条链10->11->01->00。
于是给定任意n > 0, 我们用二进制表示它为(1x), 我们希望找到(1x)在哪条链里, 这个容易,就是n的bti数m, 这条链的第一个数是2 ^ (m - 1),这条链的长度是2 ^ m - 1。然后我们想看一下(1x)在这条链的什么位置,显然它在这条链的前半段,因为开头是1。那相当于看x在它所在链到0的距离——因为前半段是倒置的。所以问题转换为,求(2 ^ m - 1)减去x变为0(或者说0变为x)的距离。递归地调用f(x)即可。
代码:
class Solution {public: int minimumOneBitOperations(int n) { if (n == 0) return 0; int m = 1; for (; m <= n; m <<= 1) ; return m - 1 - minimumOneBitOperations((m >> 1) ^ n); }};
精彩推荐
算法题——[leetcode1553]吃完n个橘子的最少天数
算法题——[leetcode1011]把所有包裹在D天内送完的最小容量
算法题——[leetcode1540]在k步内变换字符串
算法题——[leetcode1545]第n个二进制串的第k位