面试题 05.04. 下一个数

本文记录了一位程序员在解决LeetCode题目时的思路历程,从暴力解法到优化策略,详细分析了寻找封闭数字的正确方法。通过位操作,找到了下一个更大和更小的数字,反思了思考问题的深入性和效率。

题目链接:leetcode.

思路错误,想着比它大的是把最左边的1和其右边第一个0交换,比它小的是把最左边的0和其右边第一个1交换
所以9我求出来就是[10,3],而实际上是[10,6]

class Solution {
public:
    vector<int> findClosedNumbers(int num) {
        int f0 = -1, f01 = -1;
        int f1 = -1, f10 = -1;
        int tmp = num;
        for(int i = 0;i < 32;++i)
        {
        	if(num & 1)
        	{
        		if(f1 == -1)
        		{
        			f1 = i;
        		}
        		if(f0 != -1 && f01 == -1)
        		{
        			f01 = i;
        		}
        	}
        	else
        	{
        		if(f0 == -1)
        		{
        			f0 = i;
        		}
        		if(f1 != -1 && f10 == -1)
        		{
        			f10 = i;
        		}
        	}
        	num >>= 1;
        }
        cout <<f0 <<' ' << f01 << endl;
        cout << f1<<' ' << f10 << endl;
        int maxx, minn;
        if(f1 != -1 && f10 != -1)
        {
        	maxx = tmp ^ (1 << f1);
        	maxx = maxx | (1 << f10);
        }
        else
        	maxx = -1;
        if(f0 != -1 && f01 != -1)
        {
        	minn = tmp | (1 << f0);
        	minn = minn ^ (1 << f01);
        }
        else
        	minn = -1;
        return {maxx, minn};
    }
};

我太笨了,暴力暴力!不会做的时候就暴力!!!
分别向上和向下找,计算1的个数是否相同

正确思路:
下一个大的数:最右边的01变成10,再把右边的1都移到最右边
下一个小的数:最左边的10变成01,再把右边的1都向左移到01紧右边

/*
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:5.9 MB, 在所有 C++ 提交中击败了91.12%的用户
*/ 
class Solution {
public:
    vector<int> findClosedNumbers(int num) {
        //先找第一个01,和它右边的1的个数
		int cnt = 0, f01 = -1; 
		for(int i = 0;i < 30;++i)//最高位为0不算,符号位 
		{
			if((num & (1 << i)) && !(num & (1 << (i + 1))))
			{
				f01 = i;
				break;
			}
			if(num & (1 << i))
				cnt++;
		} 
		int maxx = -1;
		if(f01 != -1)
		{
			//01反转,右侧置0
			maxx = num ^ (1 << (f01 + 1));
			maxx = maxx ^ (1 << f01);
			for(int i = 0;i < f01;++i)
			{
				if(maxx & (1 << i))
					maxx = maxx ^ (1 << i);
			}
			int t = 1; 
			while(cnt--)
			{
				maxx += t;
				t <<= 1;
			}
		}
		//找第一个10,和它右边的1的个数
		int f10 = -1;
		cnt = 0; 
		for(int i = 1;i < 32;++i)
		{
			if((num & (1 << i)) && !(num & (1 << (i - 1))))
			{
				f10 = i;
				break;
			}
			if(num & (1 << (i - 1)))
				cnt++;
		} 
		int minn = -1;
		if(f10 != -1)
		{
			//先反转 
			minn = num ^ (1 << f10);
			minn = minn ^ (1 << (--f10));
			//再置0
			for(int i = 0;i < f10;++i)
			{
				if(minn & (1 << i))
					minn = minn ^ (1 << i);
			} 
			while(cnt--)
			{
				minn = minn ^ (1 << (--f10));
			}
		}
		return {maxx, minn};
    }
};

太辛苦了,这小破题做了一天。位运算还是一步一步来吧,别想着怎么把它一步到位,我脑子不够的○| ̄|_

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值