高斯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

拼凑结果

参考文章

貌似需要翻墙

相关推荐
遥感知识服务6 小时前
从局部阈值、双极化到暗地表剔除:NASA OPERA DSWx-S1全球动态水体算法拆解
大数据·人工智能·深度学习·神经网络·算法·机器学习
晚风醉蝶6 小时前
1-13-TimSort
算法
ZJU_统一阿萨姆6 小时前
【算子开发】算子融合与Softmax_LayerNorm实现
人工智能·算法·语言模型·硬件架构
叩码以求索8 小时前
浅谈:前序遍历反转法求解N叉树的后序遍历
算法
北风toto9 小时前
中缀、前缀、后缀表达式
算法·软件设计师
听取WA声一片(无恶意)9 小时前
CSP-J/CSP-S 深度优先搜索(DFS)完全讲义
c++·算法·深度优先
码流怪侠10 小时前
2026年8月GitHub热榜深度拆解:Agent Skills席卷开源圈,一个“技能包“收割5万星
算法·程序员·github
hold?fish:palm10 小时前
30 两两交换链表中的节点
数据结构·算法·链表
Nil20810 小时前
leetcode 98验证二叉搜索树
算法·leetcode·职场和发展
不正经学生10 小时前
C语言结构体:自定义数据类型,让变量打包出行
java·c语言·开发语言·数据结构·算法