n&(n-1)作用:将n的二进制表示中的最低位为1的改为0。
一个简单的例子:
可能会有人问:那10011(n-1)不是比10100(n)还多弄出了一个1吗?所以这时候就需要“&”运算的参与了。“n-1”所造成的多出的1,在和“n”相“&”之后,一定会被消除为0,因为其之所以能多出1,一定是因为原先的“n”在对应位置上为0,借位不得而成的1。
应用:
while(n>0){
count ++;
n&=(n-1);
}
例题:
原题链接
代码如下
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int count=0;
while(n!=0){
n&=(n-1);
count++;
}
return count;
}
}
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc =new Scanner(System.in);
int n=sc.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++)a[i]=sc.nextInt();
for(int i=0;i<n;i++){
int count=0;
while(a[i]>0){
a[i]&=a[i]-1;
count++;
}
a[i]=count;
}
for(int i=0;i<n;i++){
System.out.print(a[i]+" ");
}
}
}
n > 0 && ((n & (n - 1)) == 0 )
解释((n & (n-1)) == 0):
如果A&B==0,表示A与B的二进制形式没有在同一个位置都为1的时候。
那么本题到底啥意思??
不妨先看下n-1是什么意思。
令:n=1101011000(二进制,十进制也一样),则
n-1=1101010111。
n&(n-1)=1101010000
由此可以得出,n和n-1的低位不一样,直到有个转折点,就是借位的那个点,从这个点开始的高位,n和n-1都一样,如果高位一样这就造成一个问题,就是n和n-1在相同的位上可能会有同一个1,从而使((n & (n-1)) != 0),如果想要
((n & (n-1)) == 0),则高位必须全为0,这样就没有相同的1。
所以n是2的幂或0。
n&-n或n&(~n+1)的作用: 保留二进制下最后出现1的位置的数字,其余位置置0;
例题:
import java.util.Scanner;
public class Main{
// lowbit函数只保留n的二进制最低位的1
public static int lowbit(int n){
return n&-n;
//return n&((~n)+1);
}
public static void main(String[] args){
Scanner sc =new Scanner(System.in);
int n=sc.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++)a[i]=sc.nextInt();
for(int i=0;i<n;i++){
int count=0;
while(a[i]>0){
a[i]-=lowbit(a[i]);//把二进制最低位的1减去,能减多少次,其二进制就有多少个1
count++;
}
a[i]=count;
}
for(int i=0;i<n;i++){
System.out.print(a[i]+" ");
}
}
}
n>>k&1的作用:可以算出n的二进制表示中,从低到高第k位是0还是1(最低位为第0位)。
举例:n=10,二进制表示:1010,假设求第3位(从0开始)是多少?
n>>3=0001,0001&1=1,所以第三位是1(1010)
原理:
原题链接
对字符数组内容进行翻转,左右指针向中间遍历,交换首尾指针指向的字符。交换采用异或操作,可以不使用额外变量。
代码如下:
class Solution {
public void reverseString(char[] s) {
int l=0,r=s.length-1;
while(l<r){
s[l]^=s[r];//s[l]=s[l]^s[r]
s[r]^=s[l];//s[r]=s[r]^s[l]=s[r]^(s[l]^s[r])=s[l]
s[l]^=s[r];//s[l]=s[l]^s[r]=(s[l]^s[r])^s[l]=s[r]
l++;
r--;
}
}
}
原题链接
2023.06.03 二刷
题解区里看到有人引用国外的一个短小精悍的题解:
示例:
nums = “----->–>”; k =3
result = “–>----->”;
过程
reverse “----->–>” we can get “<–<-----”
reverse “<–” we can get “–><-----”
reverse “<-----” we can get “–>----->”
代码如下:
class Solution {
public void rotate(int[] nums, int k) {
int n=nums.length;
k%=n;//k可能比nums大,但是nums右移n位还是原来的nums
reverse(nums,0,n-1);//反转区间两端都为闭
reverse(nums,0,k-1);
reverse(nums,k,n-1);
}
//对数组指定区间进行反转
public void reverse(int[] nums,int l,int r ){
while(l<r){
// 基于异或运算的交换律和结合律,以及a^a=0,a^0=a;
nums[l]^=nums[r];//nums[l]=nums[l]^nums[r]
nums[r]^=nums[l];//nums[r]=nums[r]^nums[l]^nums[r]=nums[l]
nums[l]^=nums[r];//nums[l]=(nums[l]^nums[r])^nums[l]=nums[r]
l++;
r--;
}
}
}