目次
こんにちは、お元気ですか、私は小さな灰色の類人猿です!バグを書くことができるスーパープログラマー!
最近、ブルーブリッジカップ関連のテスト質問を行うと、配列要素の順列と組み合わせの使用が非常に広範囲であり、一般的な順列と組み合わせタイプの質問もデータ構造とアルゴリズムの典型的な例であることがわかりました。今日は共有します通常の開発プロセスでは、順列と組み合わせのいくつかのタイプとソリューションがよく使用されます。
1つは、配列要素の組み合わせです。
m個の数値がn要素の配列arrから取得され(順序に関係なく、繰り返しがない)、新しい配列newarrに配置される場合、一般的な考え方は再帰的な考え方を使用することです。
- 配列arrからn個の数値を取得すると、最初のarrの数値をnewarrの最初の要素として取得できます。
- arrの最初の要素を取り出した後、再帰的な実装を使用して、次のn-1要素からm-1要素を取り出します(これは最初のステップのサブ問題です)。
- 0個の要素を取り出す必要がある場合、結合されたタスクが完了します
- 最初のステップに戻り、forループを使用して2番目の要素を取り出し(次の組み合わせを開始)、合計でnm回ループします。
特定の実装は、直接呼び出して使用できる次の関数で表示できます。
/**
* 在数组中选取n个数进行组合(不考虑顺序且数据不重复)
* @param 待处理的数组
* @param newarr 组合后得到的数组
* @param k 从哪一个下标的元素开始取
* @param n 需要取出元素的个数
* */
private static void combination(int[] arr,int[] newarr, int k,int n) {
//当需要取出的元素个数是0时,说明组合完成
if (n==0) {
for (int i = 0; i < newarr.length; i++) {
System.out.print(newarr[i]);
}
System.out.println();
return;
}
for (int i = k; i <= arr.length-n; i++) {
newarr[newarr.length-n] = arr[i]; //将提取出来的数依次放到新数组中
combination(arr, newarr,i+1, n-1); //按照同样的方法从剩下的元素中选出n-1个元素
}
}
テストケース:
public static void main(String[] args) {
int[] arr = {1,2,3,4}; //待处理的数组
int n = 3; //取出元素的个数
int[] newarr = new int[n]; //存放结果的数组
combination(arr, newarr, 0, n);
}
第二に、配列要素の完全な配置
n個の数値を持つ配列arrを完全に配置するために使用されるアイデアは、再帰とバックトラックです。
- n個の要素を完全に配置し、最初の要素を次の要素と順番に交換して、最初の要素を決定します
- 次のn-1要素の完全な配置(最初のステップのサブ問題と見なすことができます)は、再帰によって実装されます。
- 配列要素の順序が乱れるのを防ぐために、交換された要素を元に戻します(バックトラック思考)
特定の実装は、次の関数を見ることができます(直接使用できます)
/**
* 对数组中所有的元素进行全排列
* @param arr 待排列的数组
* @param k 确定第几个元素,是下标,从0开始
* */
private static void f(int[] arr, int k) {
//当k等于数组的长度时,说明排列完成
if (k == arr.length) {
//将排列好的数组输出
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
}
System.out.println();
}
for (int i = k; i < arr.length; i++) {
//将待确定的元素位置和后面的元素互换
int t = arr[k];
arr[k] = arr[i];
arr[i] = t;
//递归(确定第k+1个元素)
f(arr, k+1);
//回溯,将调换后的元素重新调换回来
t = arr[k];
arr[k] = arr[i];
arr[i] = t;
}
}
テストケース:
public static void main(String[] args) {
int[] arr = {1,2,3,4}; //待处理的数组
int n = 3; //取出元素的个数
int[] newarr = new int[n]; //存放结果的数组
f(arr, 0);
}
第三に、配列要素の順列と組み合わせ
n要素配列arrからm個の数を取り出し(順序に関係なく、繰り返しなし)、n個の数を完全に並べ替え、次にn個の数からm個の数を取り出して並べ替えを実現するという上記の理解により、問題は次の組み合わせとして見ることができます。上記の2つの問題。
数学の考え方によれば、最初にn個の要素の配列からm個の要素を選択し、次にすべてのm個の要素を配置することができます。
実装方法は次のとおりです。
/**
* 数组中对n个数进行全排列
* @param 待处理的数组
* @param newarr 排列后得到的数组
* @param k 从哪一个下标的元素开始处理
* @param n 处理元素的个数
* */
private static void pac(int[] arr,int[] newarr, int k,int n) {
//当n=0时,说明选取的数的个数为0,也就是组合完成
if (n==0) {
f(newarr, 0); //对组合到的新数组进行全排列
return;
}
for (int i = k; i <= arr.length-n; i++) {
newarr[newarr.length-n] = arr[i];
pac(arr, newarr,i+1, n-1);
}
}
/**
* 对数组中所有的元素进行全排列
* @param arr 待排列的数组
* @param k 确定第几个元素,是下标,从0开始
* */
private static void f(int[] arr, int k) {
//当k等于数组的长度时,说明排列完成
if (k == arr.length) {
//将排列好的数组输出
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
}
System.out.println();
}
for (int i = k; i < arr.length; i++) {
//将待确定的元素位置和后面的元素互换
int t = arr[k];
arr[k] = arr[i];
arr[i] = t;
//递归(确定第k+1个元素)
f(arr, k+1);
//回溯,将调换后的元素重新调换回来
t = arr[k];
arr[k] = arr[i];
arr[i] = t;
}
}
テストケース:
public static void main(String[] args) {
int[] arr = {1,2,3,4}; //待处理的数组
int n = 3; //取出元素的个数
int[] newarr = new int[n]; //存放结果的数组
pac(arr,newarr,0, n);
}
上記は、順列と組み合わせの3つの一般的なタイプとそれらのソリューションです。主なアイデアは、再帰とバックトラックを使用することです。最適化や不備がありますので、修正していただければ幸いです。
気分が良く、好きでフォローすることを忘れないでください!
リトルグレイエイプは一緒に進歩するためにあなたに同行します!