完美洗牌问题系列文章:

提示:很重要的思想
1.完美洗牌问题——整体交换数组的左右2部分
2.完美洗牌问题——计算位置i下次要被挤到哪个位置j?
这2个文章,都是为本文做铺垫的,循序渐进理解什么是完美洗牌问题,如何解决完美洗牌问题?


文章目录

  • 完美洗牌问题系列文章:
    • @[TOC](文章目录)
  • 完美洗牌问题的定义
  • 一、通过循环挤兑i到j,实现完美洗牌问题
  • 二、但是一个数组arr,它可能存在多个挤兑环
  • 三、通过扭转、挤兑最大那个环,破解完美洗牌问题
  • 总结

完美洗牌问题的定义

完美洗牌问题的定义:

给你一个arr,长度是偶数长度S,左边部分长度为N,右边部分长度为N
请将左边右边部分交叉组合,保证时间复杂度不会超过o(n),空间复杂度不会超过o(1)——即完美洗牌


一、通过循环挤兑i到j,实现完美洗牌问题

根据文章:2.完美洗牌问题——计算位置i下次要被挤到哪个位置j?
可以知道,我们从start=1位置出发,可以不断地调用f(arr,i,S)函数【i位置应该去哪里?j,要求j,arr长度是偶数长S】,去挤兑另一个位置j,然后当j回到start位置时,全部挤兑完成,看图:

经过一圈循环,将i的数,挤兑到j处,完成了完美洗牌问题


二、但是一个数组arr,它可能存在多个挤兑环

比如,当长度S=6时

发现了没?S=6时,N=3,而从1挤兑到2,2挤兑到4,4很快挤兑到了1,形成了一个环,另外的那些还搞不定呢!!!

所以到这里,本题的重要记忆结论来了!!!!,直接背
记结论!
记结论!
记结论!

当长度S=3^^k - 1 时:即2,8,26,80这种特定的长度时,
他们的环起点有这些:1,3,9,……,S=3^^k - 1

而且,我们求解的时候,一定要找长度最长那个环开始挤兑,这就要求,我们需要找到<=S的3^^k - 1
比如S=14这种,显然不符合特定长
那要找到哪个3^^k - 1<=14
显然k=2时,3^^k - 1=8,它死最近的<=4的特定长度。
故我们要先扭转一部分数据到左边,凑合为左边能挤兑的8长度(S=8,N=4)【然后就能用环起点挤兑了】
剩下的再看看他们能组成的最长特定长是多少?再去挤兑合适的数组。——这就是破解完美洗牌问题的方法,下面细说


三、通过扭转、挤兑最大那个环,破解完美洗牌问题

二中的举例:

(1)S=14,N=7,所以呢,咱先把那个能挤兑的整体长度8挤兑了,要求,右边有half=8/2=4这么多,要和左边的N-half那部分,相互扭转交换。
——这就是上面所说的文章1做的事情:1.完美洗牌问题——整体交换数组的左右2部分

(2)剩下的S=6长度的呢,还是不符合特定长,没法挤兑【看下图粉色部分】
一样的,我们还需要找到哪个3^^k - 1<=6
显然,k=1时,到哪个3^^k - 1 = 2<=6
2这个特定长度,先挤兑再说:也就是把L5R5放一起,
即把右边R5R6R7中,half=2/2=1这么多数,跟左边N-half这么多扭转交换,再挤兑

(3)还剩4个,仍然不是特定的长度【看上面这个图:橘黄色部分】
一样的,我们还需要找到哪个3^^k - 1<=4
显然,k=1时,到哪个3^^k - 1 = 2<=4
2这个特定长度,先挤兑再说:也就是把L6R6放一起,
即把右边R6R7中,half=2/2=1这么多数,跟左边N-half这么多扭转交换,再挤兑

(4)还剩下2个,恰好满足了特定的长度,直接挤兑即可;
最终,从最长的那个环开始挤兑,直到全部环都挤兑玩,完美洗牌问题敲定!!!!

我们先单独写
一个合规特定长度为S,循环挤兑各个环,达成这种特定长度S下的完美洗牌问题的代码【比如S=2,8,28,80这种】:
从arr的start环点开始,合规特定长度为S,最大合规满足3^^k - 1=S的k跟着来,k意味着有k个环需要挤兑
因为我不用0坐标,所有i=0开始要抠清楚arr的那些边界,
i控制最大到k个环,全部环都要挤兑完成
每次出发点从trigger=1出发,依次寻找这些环触发点:1,3,9,27,81……
cur=j就是位置x下一次需要去的地方
整体代码好好细品:

//给你一个起点,给你一个3^k-1的长度S,给你一个环的个数k,让你挨个挤兑到相应的位置public static void cycle(int[] arr, int start, int S, int k){//S=3^k-1,即长度为2,8,26,80的长度,一定有k个环需要挤兑//环有k个,每个的出发点trigger是1,3,9,27,81,,,3^k-1,共k个触发点for (int i = 0, trigger = 1; i < k; i++, trigger *= 3) {//挤兑出去之前,我是preValueint preValue = arr[start + trigger - 1];//-1是因为起点用1表示//即将去哪个位置?int cur = findNextIndex(trigger, S);//用S这个长,S/2==N去推下一个去的位置,先拿变量记住while (cur != trigger){int nextValue = arr[start + cur - 1];//tmp保存我arr[start + cur - 1] = preValue;//被挤进来preValue = nextValue;//刚刚cur处的值就作为我,要去挤兑别人的数值了cur = findNextIndex(cur, S);//nextValue去挤兑谁呢,cur开始推理}//直到最后一个元素,此时cur==trigger时,回到了原点,则最后那个nextValue放回原点arr[start + cur - 1] = preValue;//最后挤兑,本环结束}}

大流程: —— 完美洗牌问题的代码
就是不断寻找,满足满足3^^k - 1<=S的特定长度,然后扭转half这么多,凑成左边合规特定长度,再利用上面cycle函数循环去挤兑
代码细细品味:

public static void shuffle(int[] arr, int L, int R){//当洗牌长度为0就完成了所有任务while (R - L + 1 > 0){int S = R - L + 1;//区间长度int base = 3;//找一个3^k方够近S的值int k = 1;//从k==1次方开始,统计环的个数while (base < (S + 1) / 3){base *= 3;k++;//每次统计k个环}//此时3^k-1已经最接近S了,那我们可以先挤兑3^k-1这么长的的区间,//首先,需要我们拿右边的half=base-1/2这么多扭到左边,也就是把L+hanf---mid---mid+half区间调换位置//让左边组合层俩half,一个base-1这么长int half = (base - 1) >> 1;int mid = L + ((R - L) >> 1);//取数组中点,左边右边界,上中点rotate(arr, L + half, mid, mid + half);//然后洗牌左边的base-1长度cycle(arr, L, base - 1, k);//参数,L是起点,S==base-1==3^k-1这么长,k个环需要触发挤兑去L = L + base - 1;//切换我左边的L,已经搞定了base-1这么长了,剩下的右边部分继续分}}

测试一波:

public static void test(){int[] arr = {1,2,3,4,5,6,7,8};perfectShuffle(arr);for(Integer i:arr) System.out.print(i +" ");}public static void main(String[] args) {test();}

总结

提示:重要经验:

1)理解清楚完美洗牌问题的定义
2)记忆一个结论:当长度S=3^^k - 1 时:即2,8,26,80这种特定的长度时,
他们的环起点有这些:1,3,9,……,S=3^^k - 1 ,也就是说,整到一个合规特定的长度S时,要依次把这k个环全部挤兑完,就是上面说的cycle函数
3)完美洗牌问题中由于arr可能不止一个环,而且还有先搞定最大的合规特定长度S那个部分,就需要先将右边部分的half扭转交换到左边,这里就需要扭转交换函数,3次逆序,一定要掌握;
4)破解完美洗牌问题,先不断寻找,满足满足3^^k - 1<=S的特定长度,然后扭转half这么多,凑成左边合规特定长度,再利用上面cycle函数循环去挤兑
5)这个题目,笔试时只能抄写代码,面试时尽力写吧,先给面试官讲清楚思想,差不多了就行。

完美洗牌问题——核心思想与代码相关推荐

  1. 完美洗牌算法简析与代码实现

    题目需求 数组[a1,a2,a3,a4,b1,b2,b3,b4],洗牌后变成[b1,a1,b2,a2,b3,a3,b4,a4]. 不得使用额外的空间,即空间复杂度要求为O(1).因为如果用线性空间,直 ...

  2. java 洗牌_java数组之完美洗牌算法

    题目详情 有个长度为2n的数组{a1,a2,a3,...,an,b1,b2,b3,...,bn},希望排序后{a1,b1,a2,b2,....,an,bn},请考虑有无时间复杂度o(n),空间复杂度0 ...

  3. 程序员编程艺术第三十四~三十五章:格子取数问题,完美洗牌算法

    第三十四~三十五章:格子取数,完美洗牌算法 作者:July.caopengcs.绿色夹克衫.致谢:西芹_new,陈利人, Peiyush Jain,白石,zinking. 时间:二零一三年八月二十三日 ...

  4. 程序员编程艺术第三十四 三十五章 格子取数问题,完美洗牌算法

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 第三十四 ...

  5. 完美洗牌问题(打乱数组间各元素的顺序)

    除了前一篇的完美洗牌问题,还有一种洗牌,就是乱序(shuffle)的问题,将54张有序的扑克牌的顺序打乱,实现洗牌操作. 局部洗牌法 1.随机产生一个1-n的数x,做为第一张牌. 2.随机产生一个1- ...

  6. java 完美洗牌,(2)数组相关算法题目

    数组是最简单的数据结构,占据连续内存并且按顺序存储. 以下是与数组有关的算法题目. (1)查询数组中重复数字 算法思路:(1)利用hash表,没有便放进去,有就返回(Java中HashMap存数字都是 ...

  7. 关于洗牌的研究(六)——从数学到魔术之完美洗牌

    爱学习,勤思考:学数学,玩魔术.欢迎点击头部蓝字关注MatheMagician,这里有你要的奇迹! 写再前面:本系列作品由MathMagician独家首发,一共有七篇,从数学和魔术两个角度对日常生活中 ...

  8. UVa Problem 10205 Stack ’em Up (完美洗牌术)

    // Stack 'em Up (完美洗牌术) // PC/UVa IDs: 110205/10205, Popularity: B, Success rate: average Level: 1 / ...

  9. php 108张牌洗牌,完美洗牌原理大揭秘 手把手图文教程!呕心沥血的超级干货...

    原标题:完美洗牌原理大揭秘 & 手把手图文教程!呕心沥血的超级干货 先感慨一下,昨晚写到半夜,今天又修改了很多遍,我终于把这篇文章写完了. 然后自夸一下,我敢保证,你从来没有看过像这样的完美洗 ...

最新文章

  1. 2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)
  2. 企业网络推广——企业网络推广表示网站优化少不了这三大技能
  3. prometheus下载慢_Prometheus + Grafana 监控 SpringBoot
  4. qt 怎么设计个性化的滑块_小小滑块大大学问,你真的会用滑块了吗?
  5. 新零售场景下的AIPL分析
  6. ​凌云KTV点歌系统功能简介
  7. 微服务系列:服务注册与发现的实现原理、及实现优劣势比较
  8. nginx搭建文件服务器脚本,基于docker搭建nginx文件服务器的方法步骤
  9. 魔兽世界最新网通服务器列表,魔兽世界网通区,魔兽世界网通区在几区
  10. extjs中grid中行内文本或图片居中显示
  11. 西班牙夺得欧洲杯给IT业的十条启示
  12. 11.云计算平台(数据科学概论)
  13. 机器学习之逻辑回归(Logistic Regression)
  14. 毕设设计要点整理(一)——角色相关
  15. iKuai软路由模拟环境搭建
  16. 一些五笔不好打出来的字(转)-留作记念
  17. 前端学习——17——获取窗口属性,dom尺寸,让滚动条滚动
  18. 华为5g cpe 虚拟服务器,一图看懂华为5G CPE Pro
  19. JavaWeb项目搭建准备工作
  20. 深度解密Go语言之关于 interface 的 10 个问题

热门文章

  1. react-native打包发布发行(Realease)版apk,出现unable to process incoming event 'ProcessComplete'
  2. 为什么阶码使用移码表示而不用补码表示
  3. ASP和PHP开源CMS系统,可作为二次开发
  4. graylog安装总结
  5. 警惕小广告联盟,别让蝇头小利败坏了网站
  6. 快速启动某个文件夹的cmd小黑框窗口
  7. 不错的互联网9大思维图
  8. python提权_linux 提权-SUID提权
  9. 从5大挑战带你了解多模态机器学习
  10. C++/MFC工程[4]——绘制直线段