Permutation sequence

n个数的全排列,按照从下到大的顺序排列,问第k个位置的数是多少?

这个问题有几种方法,不过只有康托编码的时间复杂度是最低的。是O(n),简直凶残。

1.用next_permutation来求,这个也是leetcode上的一道题,就是求其下一个排列,然后对1234…n 运行k-1次 next_pernutation方法就能得到第k个数了

image

思想就是这样。

2.利用康托编码来求。

其实就是康托展开的逆过程。

康托展开用来求某个全排列数是第几小的数,也就是当这些数按顺序排时第几个数。

过程如下:比如求321 是 第几小的,可以这样来想:小于3的数有1和2 两个,首位确定之后后面两位有2!中情况,所以共有2*2!=4种。

小于2的数只有一个1,所以有1*1!=1种情况,最后一位是1,没有比一小的数,所以是0*0!=0

综上:小于321的数有4+1=5个,所以321是第六小的数。


逆过程就是已知这个数是第k个数,求这个数是多少,当然是知道n的值的。

第k个数就是有k-1个数比这个数小。

所以就是 k-1=an*(n-1)!+an-1*(n-2)!+....+a1*0!;


简单的,可以用暴力枚举法,调用k -1 次next_permutation()。
暴力枚举法把前k 个排列都求出来了,比较浪费,而我们只需要第k 个排列。


2.
利用康托编码的思路,假设有n 个不重复的元素,第k 个排列是a1; a2; a3; :::; an,那么a1 是
哪一个位置呢?
我们把a1 去掉,那么剩下的排列为a2; a3; :::; an, 共计n-1 个元素,n-1 个元素共有(n-1)!
个排列,于是就可以知道a1 = k/(n - 1)!。

同理,a2; a3; :::; an 的值推导如下:
k2 = k%(n - 1)!
a2 = k2/(n - 2)!

kn-1 = kn-2%2!
an-1 = kn-1/1!
an = 0


#include <iostream>
using namespace std;
#include <string>
#include <vector>

void nextPermutation(string & v)
{
	int end = v.size()-1;
	int  i = end ,k= end;
	while(i)
	{
		if (v[i]>v[i-1])
			break;
		--i;	
	}
	if (i>0)
	{
		--i;
		while(v[k]<=v[i]) 
			--k;
		swap(v[i],v[k]);

		reverse( v.begin()+i+1,  v.end() );
	}
	else
	{
		reverse( v.begin(),v.end() );
	}
}
// 调用k-1次Next Permutation
string getKthPermutation(int n ,int k)
{
	string s(n,'0');
	for ( int i =0; i<n;++i)
	{
		s[i] += i+1;
	}
	int j = k-1;
	while (j--)
	{
		nextPermutation( s);
	}
	return s;

}
int factorial (int n)
{
	int result = 1;
	for (int i = 1; i<= n;++i)
	{
		result *= i;
	}
	return result ;

}
//康托编码
template <typename sequence >
sequence kth_Permutation(const sequence & seq ,int k)
{
	 const int n = seq.size();
	 sequence s(seq);
	 sequence result;
	 int base = factorial (n-1);
	 --k;//康托编码是从0开始,即是s[0]下标是从0开始的,为一致,--k
	 for (int i = n-1; i>0; k %= base, base /= i,--i)
	 {
		 auto a = next(s.begin(),k/base);//找到第n位上的数字在排列中的位置index,这样提取的数列中的index位
		 result.push_back(*a); //再push
		 s.erase(a);//排列中数字不能重复,所以必须删除元素*a
	 }
	result.push_back(s[0]);//,注意for循环是n-1到1,只push n-1个元素,所以还要push最后一个
	return result;
}

string getPermutation(int n , int k)
{
	string s(n,'0');
	string result;
	for ( int i =0; i<n;++i)
	{
		s[i] += i+1;
	}
	return kth_Permutation(s, k);

}

int main()
{
	int n = 5, k= 2;
	//test1 康托编码
	string s ;
	s = getPermutation(n, k);
	cout<<s;
	//test2 调用netx permutation
	string s2;
	s2 = getKthPermutation(n,k);
	cout<<s2;

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值