1到n全排列的hash函数(o(n))

1到n全排列的hash函数(o(n))

  全排列的hash函数,可以利用N位变进制,一般做法是用逆序数,但时间复杂度比较大。

 

 

  设n位变进制数M,+i位逢i+1进一,显然M可表示的数的范围为[0, n!)共n!个

  要生成n个数的排列,可以先从n个数挑一个,再从剩下的n-1个数挑一下,如此反复n次。

  若最初的n个数是 0,1,2 … n-1,第一次挑选的数是t,则可以将t放入到M的n-1位,
  若第二次挑选的数是m,则 0 <= r <= n-1 且 r != t,当r等于n-1时,
  不能将r放入到M的n-2位(可以放的最大数为n-2),但是注意到r值不可能为t,
  该情况下将它的值改为t,得到的新r值肯定小等于n-2,因而可放入到M的n-2位。

  重复上面的处理,最终得到的M值与排列是一一对应的。

 

 

#include
<
algorithm
>

#include

<
cstdio
>

#include

<
cassert
>


//
template<int n> 

//
struct Factorial { enum { v = Factorial<n – 1>::v * n}; };

//


//
template<> struct Factorial<0> { enum { v = 1}; };

//


//
static const int Max_n = 12; 

//
static const int factorial[Max_n] = {  
//
0! 1! 2! .. 11!   12!= 4.8e8

//
  Factorial<0>::v, Factorial<1>::v, Factorial<2>::v,

//
  Factorial<3>::v, Factorial<4>::v, Factorial<5>::v,

//
  Factorial<6>::v, Factorial<7>::v, Factorial<8>::v,

//
  Factorial<9>::v, Factorial<10>::v, Factorial<11>::v,  

//
};




static
 inline 
bool
 init_factorial(
int
 arr[], 
int
 len) 
{

  

for
 (
int
 i 
=
 
0
, k 
=
 
1
; i 
<
 len; k 
*=
 
++
i) arr[i] 
=
 k; 
//
arr[i]为i!


  
return
 
true
;
}


int
 hash_permutation(
int
 arr[], 
const
 
int
 len)
{

  

static
 
const
 
int
 Max_n 
=
 
12
;      
//
 12!= 4.8e8


  
static
 
int
 factorial[Max_n];
  

static
 
bool
 tmp 
=
 init_factorial(factorial, Max_n);
  (

void
)tmp;
  assert(len 

>=
 
1
 
&&
 len 
<=
 Max_n);
  

//
mapped[i]记录数i最终被映射到哪个数字,index[i]记录数i在mapped数组中的位置


  
int
 mapped[Max_n], index[Max_n];
  

for
 (
int
 i 
=
 
0
; i 
<
 len; 
++
i) mapped[i] 
=
 index[i] 
=
 i;
  
  

int
 ret 
=
 
0
;
  

//
设变进制数M的+i位为(i+1)进制。从高位到低位放入数字


  
for
 (
int
 i 
=
 len 

 
1
; i 
>
 
0


i) { 
    assert(arr[i] 

>=
 
0
 
&&
 arr[i] 
<
 len);  
    

int
 k 
=
 mapped[arr[i]];     
//
mapped数组中所有的数是0,1, 2, … i的一个排列,


    ret 
+=
 k 
*
 factorial[i];    
//
因而可以将数字k放到变进制数M的+i位


    
    

int
 idx 
=
 index[i];         
//
将k从mapped数组中删除,删除k前                 


    mapped[idx] 
=
 k;            
//
先将mapped数组中最大的数(也就是i)映射到k,


    index[k] 
=
 idx;             
//
保证删除k后剩下的数恰好是0,1,2 … i-1的一个排列


  }
  

return
 ret;
}


int
 main()
{

  

const
 
int
 N 
=
 
4
;
  

int
 arr[N];
  

for
 (
int
 i 
=
 
0
; i 
<
 N; 
++
i) arr[i] 
=
 i;
  

int
 count 
=
 
0
;
  

do
 {

    printf(


 %3d:  


++
count);
    

for
 (
int
 i 
=
 
0
; i 
<
 N; 
++
i) printf(

 %2d

, arr[i]);
    printf(


  %6d\n

, hash_permutation(arr, N));
  } 

while
(std::next_permutation(arr, arr 
+
 N));
}

 

 

 

 

转载于:https://www.cnblogs.com/flyinghearts/archive/2011/05/08/2040612.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/110617.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 一个很简单很简单的静态网页(附源代码)HTML+CSS

    一个很简单很简单的静态网页(附源代码)HTML+CSS首先声明 代码中使用的爱心特效和转动的音符这个两个效果是笔者从网上找到的 具体在哪里找的我也忘了 其他部分是自己写的

    2026年2月6日
    0
  • 装水的容器大全_盛水的容器什么最好

    装水的容器大全_盛水的容器什么最好原题链接给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。说明:你不能倾斜容器。示例 1:输入:[1,8,6,2,5,4,8,3,7]输出:49解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。示例 2:输入:he

    2022年8月8日
    2
  • anaconda和python版本对照表

    anaconda和python版本对照表python2 python3 anaconda2/3 2.7.14 3.6.5 5.2.0 2.7.14 3.6.4 5.1.0 2.7.14 3.6.3 5.0.1 2.7.13 3.6.2 5.0.0 2.7.13 3.6.1 4.4.0 2.7.13 3.6.0 4.3.1 2….

    2022年5月28日
    487
  • 国内常用DNS「建议收藏」

    国内常用DNS「建议收藏」//DNS1:114.114.114.114国内移动,电信,联通通用DNS//DNS2:223.5.5.5阿里//DNS3:223.6.6.6阿里//DNS4:180.76.76.76百度

    2025年9月26日
    5
  • cuda编程基础(建站)

    一:新建CUDA项目流程(VS2013下)1.新建项目(file->New->Project)2.在项目列表中可以看见NVIDIA的CUDA项目(前提是你安装了CUDA)选择项目,添加一些必要的信息,自己定义就行3.项目生生成成功.cu文件就是跑在GPU上面的文件。文件夹里面是自动生成的一些要依赖的库文件你可以不用管二:第一个程序:HelloWorld我们通过最基本最经典的HelloWo

    2022年4月15日
    62
  • vue 重新加载页面_页面重新加载

    vue 重新加载页面_页面重新加载Vue刷新页面重新加载问题描述在加载同一路由页面的时候,vue的页面默认是不刷新的,需要重新加载数据解决方案修改App.vue在路由视图上添加一个变量isRouterAlive判断显示实现重新加载<template><!–<router-view/>–><router-viewv-if=”isRouterAlive”/></template><script>/*这个脚本主要是用来刷新页面的

    2022年10月17日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号