解法一、数位模拟
比n大的最小数就是n+1,当n+1时,以下几种情况会导致n中1的个数发生变化(或者不变)
1.n的低位连续1的个数count>1,如1011,10111,1111等,加1后使得n中1的个数减少count-1个
解决办法也很简单,加1后,将这count-1个1补到低位即可。
2.n的低位连续1的个数count=1,如101,01,10101等,加1后n中1的个数不变,答案就是n+1;
3.n的低位连续1的个数count=0,如100,1010,10等,加1后使得n中1的个数增加1.
解决办法:找到最低位的1,再找到离它最近的高位0,两者互换,再把高位0位置后面的1全部放到低位。
代码:
import java.util.*;
public class Main{public static void main(String[] args){Scanner in=new Scanner(System.in);int n=in.nextInt();// 1.求n的低位连续1的个数int count=get(n),ans=0;if(count==1){ans=n+1;}else if(count==0){int[] arr=toArray(n);int index=arr.length-1;while(index>=0&&arr[index]==0){// 1.找最低位1的位置indexindex--;}if(index==0){//只有一个1ans=(n<<1);}else{// 2.找到index前面高位的第一个0位int idx=index-1;while(idx>=0&&arr[idx]==1){idx--;}if(idx<0){//前面没0,左移1位,除了最高位,全部取反int base=0,len=arr.length;for(int i=0;i<len;i++){arr[i]=(arr[i]==0?1:0);base=(base<<1)|arr[i];}ans=((1<<len)|base);}else{//两处互换,idx后面的1全部放到低位arr[index]=0;arr[idx]=1;int base=1,i=idx+1,j=arr.length-1;while(i<j){if(arr[i]==1){if(arr[j]==0){arr[j]=1;arr[i]=0;i++;}j--;}else{i++;}}for(i=1;i<arr.length;i++){base=(base<<1)|arr[i];}ans=base;}}}else{//加1,末尾补偿count-1个连续的1int digit=1;for(int i=0;i<count-2;i++){digit=(digit<<1)|1;}ans=((n+1)|digit);}System.out.println(ans);}// 求低位连续1的个数public static int get(int n){int count=0;while((n&1)==1){n=(n>>1);count++;}return count;}//n转成bit数组public static int[] toArray(int n){int m=n,len=0;while(m!=0){len++;m=(m>>1);}int[] ans=new int[len];len--;while(n!=0){ans[len--]=(n&1);n>>=1;}return ans;}
}
解法二(博客原解):寻找01数对
找到尾部第一对01,将其变成10即可。
特殊情况
1.没有数对01,如10,1000,111等值,在最高位补0即可。
2.按逻辑,10110->11010,而10011处理后的正确答案是:11001。将01变成10后,末尾的1应该全部放到低位,保证值最小。
代码1:比特数组
import java.util.*;
public class Main{public static void main(String[] args){Scanner in=new Scanner(System.in);int n=in.nextInt();int[] arr=toArray(n);n=arr.length;int ans=0;//找到第一对“01”,将其变成“10”for(int i=n-2;i>=0;i--){if(arr[i]==0&&arr[i+1]==1){arr[i]=1;arr[i+1]=0;//i后面的1全部放到低位int j=i+1,k=n-1;while(j<k){if(arr[j]==1){if(arr[k]==0){arr[k]=1;arr[j]=0;j++;k--;}else{k--;}}else{j++;}}// 比特数组转成十进制:二进制转十进制ans=arr[0];for(int idx=1;idx<n;idx++){ans=(ans<<1)|arr[idx];}//处理结束,跳出循环break;}}System.out.println(ans);}//n转成bit数组(高位补0,方便处理)public static int[] toArray(int n){int m=n,len=0;while(m!=0){len++;m=(m>>1);}int[] ans=new int[len+1];while(n!=0){ans[len--]=(n&1);n>>=1;}ans[len]=0;return ans;}
}
代码2:充分利用java自带的api
import java.util.*;
public class Main{public static void main(String[] args){Scanner in=new Scanner(System.in);int n=in.nextInt();char[] arr=("0"+Integer.toBinaryString(n)).toCharArray();int i=arr.length-2;while(i>=0&&!(arr[i]=='0'&&arr[i+1]=='1')){i--;}arr[i]='1';arr[i+1]='0';//i后面的'1'全放到低位int j=i+1,k=arr.length-1;while(j<k){if(arr[j]=='1'){if(arr[k]=='0'){arr[k]='1';arr[j]='0';j++;k--;}else{k--;}}else{j++;}}int ans=arr[0]-'0';for(i=1;i<arr.length;i++){ans=(ans<<1)|(arr[i]-'0');}System.out.println(ans);}
}