完美洗牌问题——计算位置i下次要被挤到哪个位置j?
提示:非常重要的知识点
什么是完美洗牌问题?
完美洗牌问题的定义:
给你一个arr,长度是偶数长度S,左边部分长度为N,右边部分长度为N
请将左边右边部分交叉组合,保证时间复杂度不会超过o(n),空间复杂度不会超过o(1)——即完美洗牌
一、审题
示例:看图:
最后L与R交叉组合放置
显然
L从1234位置去了2468位置
R从5678位置去了1357位置
二、解题:计算位置i下次要被挤到哪个位置j
有啥关系呢
看表
i | j |
---|---|
1 | 2 |
2 | 4 |
3 | 6 |
4 | 8 |
5 | 1 |
6 | 3 |
7 | 5 |
8 | 7 |
S=8,N=4
位置i<=N时,去了2i的偶数位置【本就是1234去偶数位置】
位置I>N时,去了2*(i-N)-1位置【本质上就是让i向左平移N个位置到1234,然后去奇数位置】
显然代码很好写,arr,目前长度是S,在位置i处,下一次要被挤到哪里去呢?用f(arr,i,S)来算j:
//重要的挤兑环找即将去的位置,看i与N的关系,S==2N
public static int findNextIndex(int i, int S){
int N = S >> 1;
if (i > N) return 2*(i - N) - 1;//向左平移N位的奇数位置
else return 2 * i;//i<=N,就是偶数位置
}
总结
提示:重要经验:
1)熟悉完美洗牌问题的定义
2)知道偶数长度S情况下,计算i下次要被挤去过的位置j的函数如何求