题目论述:
引用
两个序列由相同的字母组成,只是次序不同
两个序列的“乱序”是指
任在一个序列中选择两个元素,看在另一个序列中是否顺序不同
问题是如何数出总共有多少“乱序”
比如有两个序列
序列1为:
1,2,4,3
序列2为
2,4,1,3
序列1中(1,2)在2中是(2,1),这就是一个乱序;(1,4)在2中式(4,1)还是乱序
;逐个检查过去,数一数,就是两个序列的“乱序数”
以下是我的一些看法,可能有些疏忽或差错,还望知道。
引用
个人看法:
本题和最大字段和有点相像
法一:每一对进行判断(还有先比对其是不是相同二元组)
s1(i,j);
s2(i,j);
for(;i<N;)
for(j=i+1;j<N;)
for(;m<N;)
for(n=m+1;n<N;) test(s1(i,j),s2(m,n));
★时间复杂度O(n^4)
上述算法,简单的修改一下,就可稍微减少复杂度。
for(;i<N;)
for(j=i+1;j<N;)
for(;m<N;) s2[m]=s1[i];m;
for(;n<N;) s2[n]=s1[j];n;
test(i,j,m,n);
★时间复杂度O(n^3),Simple()
法二、要达到O(nlogn),一般情况下采用分治算法,将规模每次缩小至原来的一半。
分治法的相关定义:
即T(1) = O(n)
T(n) = 2T(n/2) + O(n)
when n=2^i
then T(n) = O(nlogn)
So,here is more thinking
把是s(0,n)分成s(0,n/2)和s(n/2,n)
s1和 s2 same divided into two halves,and compare each half by itself
for the middle one,we use this:
question:s1(l,u) and s2(l,u) and middle = (l+u)/2
此部分的二元组个数为:n^2 (n指当前分半后的规模),即(n/2)2
由此看来,运算的规模还是没有有效地降低下来,我们应该想想其他办法。
。。。。。
。。。。。
想想,应该是二元组比对的效率在影响,所以应该从这方面入手
其二,大概有n^2个二元组,所以应该至少n^2次比较,而并非上述的(nlogn)
法三、以尾字符为标志
for(i=1;N;)
setA:[0...i-1]
for(j;N;)
s2[j] == s1[i] break;
setB:[0...j-1]
setA-setB;
上述主要时间复杂度在setA-setB上,即是求出两集合(差)运算。可以先排序,
使用一般的插入排序,耗时nlogn,然后以n时间集合运算。综上所述,
★时间复杂度O(n^2logn),OutofOrder()
法四、位置标志法
此法是对法一的改进
算法描述:
tmp1[];辅助数组
tmp2[];辅助数组
for(;N;)
for(;N;) test(tmp1[i],tmp1[j],tmp2[i],tmp2[j]);
★时间复杂度O(n^2),Best()
其中,带★的后三种我都实现了,下面逐一论述:
原始序列的产生不再赘述(为简化,简单的为0到n间的数,就这一点后面还有论述,关于排序部分);
算法一:int Simple(int *s1,int *s2,int n)
{
//improved simple method
int i,j,p,q,sum;
sum = 0;
for (i = 0;i < n-1;++ i)
{
for (j = i+1;j < n;++ j)
{
//find the first number in s2[]
for (p = 0;p < n;++ p)
if (s2[p] == s1[i]) break;
//find the second number in s2[]
for (q = 0;q < n;++ q)
if (s2[q] == s1[j]) break;
if (!test(i,j,p,q)) sum ++;
}
}
return sum;
}
其中test()函数是判断四个元素是否同一顺序,即升序,降序,以此决定两元组是否顺序相同。上述时间复杂度位O(n^3).
算法二:int OutofOrder(int *setA,int *setB,int n)
{
//sum up the out order number
int i,j,k,sum,*tmp1,*tmp2;
tmp1 = new int [n];
tmp2 = new int [n];
sum = 0;
for (i = 1;i < n;++ i)
{
for (j = 0;j < n;++ j)
if (setB[j] == setA[i]) break;
//copy the temp array for summation
for (k = 0;k < i;++ k) tmp1[k] = setA[k];
for (k = 0;k < j;++ k) tmp2[k] = setB[k];
InsertSort(tmp1,i);
InsertSort(tmp2,j);
sum += Margin(tmp1,0,i,tmp2,0,j);//i,j not included
}
delete [] tmp1;
delete [] tmp2;
return sum;
}
上述Margin()函数就是下面的集合差集的运算:
int Margin(int *setA,int a1,int a2,int *setB,int b1,int b2)
{
//compute the balance number
if (a1 == a2) return 0;
if (b1 == b2) return a2 - a1;
if (setA[a1] == setB[b1]) return Margin(setA,a1+1,a2,setB,b1+1,b2);
else if (setA[a1] < setB[b1]) return 1+Margin(setA,a1+1,a2,setB,b1,b2);
else return Margin(setA,a1,a2,setB,b1+1,b2);
}
此算法的时间复杂度最好保持在O(n^2logn),nlogn就是上面的集合做差集的时间复杂度。
算法三:int Best(int *s1,int *s2,int n)
{
//improved method using T(n^2)
int i,j,*tmp1,*tmp2,sum;
sum = 0;
//suppose that all these number are in sequence from 1...n
tmp1 = new int [n];
tmp2 = new int [n];
SignPlace_2(s1,tmp1,n);
SignPlace_2(s2,tmp2,n);
for (i = 0;i < n;++ i)
for (j = i+1;j < n;++ j)
if (!test(tmp1[i],tmp1[j],tmp2[i],tmp2[j])) sum ++;
return sum;
}
上面的SignPlace_2()是对无序数组求解其顺序排序后在原序列位置的函数,比如:
原序列: 1 4 5 2
位置序列:0 3 1 2
关于这个函数,我写了三个版本,一个版本是建立在原序列是不间断的一连串数字组成,所以实现起来很简单,另一版本是一个通用版本,可以忽略上述的限制条件,使用类似插入排序的算法实现。最后一个版本采用空间换取时间的方法,是对版本一的扩展。一下是相应代码:
void SignPlace_2(int *s,int *tmp,int n)
{
//numbers are not in sequence
//O(nlogn)
int i,j,temp,*p;
p = new int [n];
//copy s[] to p[]
for (i = 0;i < n;++ i) p[i] = s[i];
tmp[0] = 0;
for (i = 1;i < n;++ i)
{
//the current palce i
temp = p[i];
for (j = i;j > 0&&temp < p[j-1];-- j)
{
p[j] = p[j-1];
tmp[j] = tmp[j-1];
}
p[j] = temp;
tmp[j] = i;
}
}
void SignPlace_3(int *s,int *tmp,int n)
{
//use more place for less time
//O(SIZE)
int i,j,*p;
p = new int [SIZE];
j = 0;
for (i = 0;i < SIZE;++ i) p[i] = -1;
for (i = 0;i < n;++ i) p[s[i]] = i;
for (i = 0;i < SIZE;++ i)
if (p[i] != -1) tmp[j++] = p[i];
delete [] p;
}
此算法时间复杂度达到n^2(如果SIZE<n*n的话)。
综述,实验的测试结果(n=1000):
Simple: 2433
OutofOrder: 671
Best: 15
单位ms.
或许还有更优的算法来实现这一问题,我也在继续思考,不过,个人感觉既然是比对二元组,而二元组共有n^2级别个,时间复杂度总要在n^2以上吧?但是其他一些算法,比如最大字段和、字符串匹配等,不都越过了数量这一坎了嘛。
分享到:
相关推荐
ORCA(序数回归和分类算法)是一个 MATLAB 框架,包括一系列与发表在 IEEE 知识和数据工程汇刊上的论文“序数回归方法:调查和实验研究”相关的序数回归方法。 ORCA 为序数回归提供序数分类算法和性能指标的实现和...
序数法是一种求解全排列问题的方法,它通过逆序数和序数的概念,建立了排列、逆序数序列和序数之间的一一对应关系。在数学中,全排列是指从给定的n个不同元素中,按照一定的顺序排列出来所有可能的组合方式。 首先...
排列生成算法,序数法,C语言源代码 首先生成中介数,由中介数确定排列。
OrdinalEntroPy是一个Python 3软件包,提供了几种时间有效的,基于序数模式的熵算法,用于计算一维时间序列的复杂性。 该程序包包含以下熵方法: [反向加权色散熵(RWDE)] 安装 重要的: 当前OrdinalEntroPy不...
函数 OPsequence [1,2] 根据给定顺序和延迟从一维时间序列 indata 计算序数模式的分布和序列(请注意,此高效版本仅支持订单 = 1…8) 笔记1 序数模式的顺序定义为 [1,3,7,8],即 order = n-1 对于序数模式的顺序 n...
作业车间调度问题(Job...令,则L为任务集的总工序数。其中,各工序的加工时间已确定,并且每个作业必须按照工序的先后顺序加工。调度的任务是安排所有作业的加工调度排序,约束条件被满足的同时,使性能指标得到优化。
首先,我们要明白序数是用来描述物体在序列中的位置的,如第一、第二、第三等。在本课件中,通过生动有趣的小动物住在几楼的情境,引导孩子们理解和学习序数。例如,"小动物住在几楼?"这样的问题,旨在让孩子们识别...
序数回归算法是一种统计学方法,常用于处理具有顺序关系但非等距的响应变量问题。在数据分析领域,它被广泛应用于预测具有等级或类别顺序的输出,如满意度调查(非常满意、满意、一般、不满意、非常不满意)或医学...
在IT领域,遇到“无法定位序数”的问题时,通常是指在尝试运行某个程序或调用某个DLL文件中的函数时,系统无法找到该函数所在的地址。这类问题常见于Windows操作系统中,尤其是当某些系统文件损坏或者更新不完整时。...
序数告诉我们某个物体在序列中的位置。例如,"排第4"指的是在一系列物体中处于第四位的那个。题目中出现的序数有1、4、3等,它们分别对应着不同的位置。 3. **基数与序数的结合**: - 在实际问题中,基数和序数...
函数 eCE = CondEn( x, delay, order, windowSize ) 从滑动窗口中的 1D 时间序列有效地计算序数模式的条件熵,用于顺序模式的 1...8 阶 [1]。 在...
序数法全排列 ...序数法全排列可以通过一些改进方向来提高其效率,例如:使用并行计算来加速算法,使用更高效的存储方法来减少内存占用等。 序数法全排列是一种高效的全排列生成算法,广泛应用于很多领域。
总的来说,排列生成算法是组合优化和算法设计中的基础工具,对理解和掌握计算机科学中的问题求解技巧至关重要。通过深入学习和实践这两种方法,不仅可以提升编程能力,还能培养解决问题的逻辑思维。
求逆序数
在MATLAB环境中,序数微分方程(Ordinary Differential Equations, ODE)是描述许多物理、工程和生物系统动态行为的基本工具。本话题主要关注如何利用MATLAB开发一个功能,该功能能够从给定的序数微分方程自动生成对应...
用序数法生成全排列,java语言,希望有帮助
这篇文档是关于中班幼儿数学教育的一个教案,主要聚焦于教授5以内的序数概念。序数是指在一组有序的对象中,每个对象所处的位置,例如第一、第二、第三等。这个活动旨在帮助孩子们理解并掌握序数的概念,并在实际...
2.4.1 序数法 2.4.2 字典序法 2.4.3 轮转法 2.5 组合生成算法 .2.6 应用举例 习 题 第三章 容斥原理 3.1 引 言 3.2 容斥原理 3.3 几个重要公式 3.4 错位排列 3.5 有限制的排列 3.6 棋阵...