高斯Hack算法

背景

leetcode时,碰到一题需要求解nbit中选择mbit的所有组合集,我只想到了递归求解,没啥问题,但是在官方题解中看到了牛逼的方法(Gosper's Hack),故记录一下。

4bit中2个1的情况

  • 0011b
  • 0101b
  • 0110b
  • 1001b
  • 1010b
  • 1100b

解法

递归求解

java 复制代码
/**
 *
 * @param retain 剩余可选1的个数
 * @param start 下一个可选坐标,范围[0,max)
 * @param max 最大边界值
 * @param val 路径val
 * @param result 结果集
 */
private void getSelectOptions(int retain, int start, int max, int val, List<Integer> result){
    if (retain == 0){
        result.add(val);
        return;
    }
    if (start >= max){
        return;
    }
    // 这个位置不填1
    this.getSelectOptions(retain,  start+1, max, val, result);
    // 这个位置填1
    this.getSelectOptions(retain-1,  start+1, max, val | (1 << (max - 1 - start)),result);
}

// 获取结果
List<Integer> selectOptions = new LinkedList<>();
this.getSelectOptions(numSelect, 0, 12, 0, selectOptions);

这个有个缺点,就是遍历了所有的case。个人感觉不是很优雅

Gosper's Hack

思路

人工写出4个bit2个1的所有场景,可以这么写0011b,0101b,0110b,1001b,1010b,1100b

它的处理步骤如下:

  • 找到最右边的1,假设位置为i
    从[i,31]中找到最右端的1,假设替换位置为j(j>i)
    [0,j)中所有的1全部移到最右边
    循环处理

干,语文不好,描述的不太清楚,可以看看参考文章

代码

java 复制代码
/**
* 获取所有bit组合数
* @param limit 总共bit数
* @param select 选取的bit数
* @return
*/
public static List<Integer> getAllBitCombination(int limit, int select){
	// 边界值处理
   if (limit >= 31 || limit <= 0 || select <= 0 || limit < select){
       return new LinkedList<>();
   }
   List<Integer> result = new LinkedList<>();
   int val = (1 << select) - 1, r, t;  //1
   int max = 1 << limit; //2
   while (val < max){ //3
       // 将符合条件的数加入结果集
       result.add(val);//4
       // 获取val中最右边的1
       r = val & -val;//5
       // 最右边的1进位左移,替换左边的第一个0槽位
       t = val + r;//6
       val = (((val ^ t) / r)  >> 2)| t;//7
   }
   return result;
}

解读

测试case

4bit中里面存在2个1的解集

limit=4select=2

步骤1

获取最小符合条件的解

  • 1 << 2 => 0100b => 4
  • (1<<2)-1 => 0011b => 3
步骤2

获取最大边界值
1<<4 => 10000 => 16

步骤3

循环获取值,知道超过边界值

步骤4

加有效的结果集加入,或者可以直接进行结果处理

步骤5

获取val中最右边的1,例如011010对应的结果为000010

步骤6

最右边的一向左扫描,替换首个碰到的零。例如011010变成011100

步骤7
(val^t)

获取步骤6中变更的路径

bash 复制代码
val                                           0 1 1 0 1 1 0 b
r                                             0 0 0 0 0 1 0 b
t                                             0 1 1 1 0 0 0 b
val^t                                         0 0 0 1 1 1 0 b
(val^t)/r

处理相对偏移量。移除右边的零,因为要将所有的1放到右边

bash 复制代码
val                                           0 1 1 0 1 1 0 b
r                                             0 0 0 0 0 1 0 b
t                                             0 1 1 1 0 0 0 b
val^t                                         0 0 0 1 1 1 0 b
(val^t)/r                                     0 0 0 0 1 1 1 b
((val^t)/r)>>2

移除两个变更点,原来是1的变成0,原来是0的变成1

bash 复制代码
val                                           0 1 1 0 1 1 0 b
r                                             0 0 0 0 0 1 0 b
t                                             0 1 1 1 0 0 0 b
val^t                                         0 0 0 1 1 1 0 b
(val^t)/r                                     0 0 0 0 1 1 1 b
((val^t)/r)>>2                                0 0 0 0 0 0 1 b
(((val^t)>>2/r)|t

拼凑结果

参考文章

貌似需要翻墙

相关推荐
pianmian13 小时前
python数据结构基础(7)
数据结构·算法
好奇龙猫5 小时前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法
sp_fyf_20245 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
香菜大丸6 小时前
链表的归并排序
数据结构·算法·链表
jrrz08286 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
oliveira-time6 小时前
golang学习2
算法
南宫生7 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
懒惰才能让科技进步8 小时前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝
Ni-Guvara8 小时前
函数对象笔记
c++·算法
泉崎8 小时前
11.7比赛总结
数据结构·算法