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

拼凑结果

参考文章

貌似需要翻墙

相关推荐
阿Y加油吧1 分钟前
堆 / 优先队列专题二刷笔记:前 K 个高频元素 & 数据流的中位数
java·笔记·算法
Chase_______2 分钟前
LeetCode 2090 题解:半径为 k 的子数组平均值,定长滑动窗口经典题一文搞懂
算法·leetcode·职场和发展
MicroTech20252 分钟前
微算法科技(NASDAQ :MLGO)量子图像加权平均滤波:以量子优势重构图像处理效率与精度
科技·算法·重构
jieyucx3 分钟前
Go 语言函数入门:定义、参数、返回值
c++·算法·golang·入门·函数
Brilliantwxx4 分钟前
【C++】认识标准库STL(1)
开发语言·c++·笔记·程序人生·算法
啦啦啦_99998 分钟前
2. 梯度下降算法分类 & 梯度下降与正规方程对比
人工智能·算法·分类
CHANG_THE_WORLD8 分钟前
gc.py 功能介绍:PDF 对象流还原工具(用于 pdfium 测试)
算法·pdf
沙白猿9 分钟前
代码随想录 28(动态规划)
算法·动态规划
wuweijianlove15 分钟前
算法复杂度与工程性能的双重度量体系技术7
算法
小年糕是糕手20 分钟前
【C/C++刷题集】栈、stack、队列、queue核心精讲
c语言·开发语言·数据结构·数据库·c++·算法·蓝桥杯