算法笔记

这篇博客介绍了Java中的算术右移和逻辑右移的区别,强调了在处理负数时逻辑右移的重要性。同时,详细讲解了回溯算法的概念和递归实现,提供了一个通用的回溯法模板。还涵盖了求最大公约数、数组去重、字符串拼接优化以及异或运算的基本性质。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法笔记

1.判断奇数偶数

为真为奇数

(k & 1) == 1
2.double计算比int要慢,所以中间记录的值要设成int型,最后返回的时候再转换成double
int x=10return 1.0*x;
迭代器
Iterator<类型> iterator=迭代对象.iterator();
分割符
String s="sdj-kad";
        for (String s1 : s.split("-")) {
            System.out.println(s1);
        }

结果:
sdj
kad
    
 String s="sdj-ka-d";
        for (String s1 : s.split("-",2)) {
            System.out.println(s1);
        }

结果:
sdj
ka-d

反转链表(拉不拉东)

ListNode reverse(ListNode head) {
    if (head.next == null) return head;
    ListNode last = reverse(head.next);
    head.next.next = head;
    head.next = null;
    return last;
}
值得一提的时候,在 Java 中,以下代码会 超时。这就不得不讲一讲 Java 中的 算术右移 和 逻辑右移 。

算术右移 >> :舍弃最低位,高位用符号位填补;
逻辑右移 >>> :舍弃最低位,高位用 0 填补。
那么对于负数而言,其二进制最高位是 1,如果使用算术右移,那么高位填补的仍然是 1。也就是 n 永远不会为 0。所以下面的代码会超时 TLE。

Java

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count = 0;
        while (n != 0) {
            count += n & 1;
            n >>= 1;
        }
        return count;
    }
}

在 Java 中需要使用逻辑右移,即 >>> ,while 的判断条件才能是 n != 0 。正确的代码如下:

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count = 0;
        while (n != 0) {
            count += n & 1;
            n >>>= 1;
        }
        return count;
    }
}
# bit操作
& 符号,x & y ,会将两个十进制数在二进制下进行与运算
| 符号,x | y ,会将两个十进制数在二进制下进行或运算
^ 符号,x ^ y ,会将两个十进制数在二进制下进行异或运算
<< 符号,x << y 左移操作,最右边用 0 填充
>> 符号,x >> y 右移操作,最左边用 0 填充
~ 符号,~x ,按位取反操作,将 x 在二进制下的每一位取反

# 整数集合set位运算
# 整数集合做标志时,比如回溯时的visited标志数组
vstd 访问 i :vstd | (1 << i)
vstd 离开 i :vstd & ~(1 << i)
vstd 不包含 i : not vstd & (1 << i)

并集 :A | B
交集 :A & B
全集 :(1 << n) - 1
补集 :((1 << n) - 1) ^ A
子集 :(A & B) == B
判断是否是 2 的幂 :A & (A - 1) == 0
最低位的 1 变为 0 :n &= (n - 1)
最低位的 1:A & (-A),最低位的 1 一般记为 lowbit(A)


回溯算法:

回溯法是一种算法思想,而递归是一种编程方法,回溯法可以用递归来实现。

回溯法的整体思路是:搜索每一条路,每次回溯是对具体的一条路径而言的。对当前搜索路径下的的未探索区域进行搜索,则可能有两种情况:

当前未搜索区域满足结束条件,则保存当前路径并退出当前搜索;
当前未搜索区域需要继续搜索,则遍历当前所有可能的选择:如果该选择符合要求,则把当前选择加入当前的搜索路径中,并继续搜索新的未探索区域。
上面说的未搜索区域是指搜索某条路径时的未搜索区域,并不是全局的未搜索区域。

回溯法搜所有可行解的模板一般是这样的:

res = []
path = []

def backtrack(未探索区域, res, path):
    if path 满足条件:
        res.add(path) # 深度拷贝
        # return  # 如果不用继续搜索需要 return
    for 选择 in 未探索区域当前可能的选择:
        if 当前选择符合要求:
            path.add(当前选择)
            backtrack(新的未探索区域, res, path)
            path.pop()

backtrack 的含义是:未探索区域中到达结束条件的所有可能路径,path 变量是保存的是一条路径,res 变量保存的是所有搜索到的路径。所以当「未探索区域满足结束条件」时,需要把 path 放到结果 res 中。
path.pop() 是啥意思呢?它是编程实现上的一个要求,即我们从始至终只用了一个变量 path,所以当对 path 增加一个选择并 backtrack 之后,需要清除当前的选择,防止影响其他路径的搜索。

求最大公约数
 //这个函数就是求最大公约数
	public static int gcd(int a, int b) {;
		if (b == 0) 
			return a;
		//如果一开始a小于b,那么下一个次的迭代就是互换顺序,往后的a都大于b
		return gcd(b, a % b);
	}
数组去重通解&&双指针解法
public int removeDuplicates(int[] nums) {
        return process(nums, 2);
    }
//k代表保留个数,此时就是保留两个chon
    int process(int[] nums,int k){
        int u=0;
        for (int x : nums) {
            if(u<k||nums[u-k]!=x){
                nums[u++]=x;
            }
        }
        return u;
    }
看到要求两个整数 x,y 如何拼接得到结果更大时,就想到先转字符串,然后比较 x+y 和 y+x。这是经验了。
public String largestNumber(int[] nums) {
    int n = nums.length;
    String[] ss = new String[n];
    for (int i = 0; i < n; i++) ss[i] = "" + nums[i];
    Arrays.sort(ss,(a,b)->{
        String sa=a+b;
        String sb=b+a;
        return sb.compareTo(sa);
    });
    StringBuilder sb = new StringBuilder();
    for (String s : ss) sb.append(s);
    int len = sb.length();
    int k = 0;
    while (k < len - 1 && sb.charAt(k) == '0') k++;
    return sb.substring(k);
}
无穷大量可用0x3f3f3f3f来定义
int INF = 0x3f3f3f3f;
异或基本知识!
  • x ⊕ x = 0
    x ⊕ y = y ⊕ x
    (x⊕ y) ⊕ z = x ⊕ (y ⊕z)
    x ⊕ y ⊕ y = x
    对于任意的 i 属于整数,有4i ⊕ (4i+1) ⊕ (4i+2) ⊕ (4i+3)=0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值