华为OD机考E卷100分题 - 第k个排列

最新华为OD机试

题目描述

给定参数n,从1到n会有n个整数:1,2,3,…,n,这n个数字共有n!种排列。

按大小顺序升序列出所有排列的情况,并一一标记,

当n=3时,所有排列如下:

“123” “132” “213” “231” “312” “321”

给定n和k,返回第k个排列。

输入描述

  • 输入两行,第一行为n,第二行为k,
  • 给定n的范围是[1,9],给定k的范围是[1,n!]。

输出描述

输出排在第k位置的数字。

示例1

输入

3
3
12

输出

213
1

说明

3的排列有123,132,213…,那么第三位置就是213

示例2

输入

2
2
12

输出

21
1

说明

2的排列有12,21,那么第二位置的为21。

解题思路

常见的递归解法

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        int n, k;
        Vector<String> lines = new Vector<String>();
        Scanner scanner = new Scanner(System.in);

        // 读取 n 和 k
        n = scanner.nextInt();
        k = scanner.nextInt();

        // 如果 n 等于 1,则直接输出 1 并结束程序
        if (n == 1) {
            System.out.println("1");
            return;
        }

        // 初始化 nums 数组,存储 1 到 n 的整数
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = i + 1;
        }

        // 初始化结果列表
        List<String> result = new ArrayList<>();

        // 递归函数,用于生成所有排列
        generatePermutations(nums, "", result, k);

        // 对结果列表进行排序
        Collections.sort(result);

        // 输出第k个排列
        System.out.println(result.get(k - 1));
    }

    public static void generatePermutations(int[] nums, String current, List<String> result, int k) {
        // 如果数字数组为空,将当前结果添加到结果列表中
        if (nums.length == 0) {
            result.add(current);
            return;
        }

        // 遍历当前数字数组
        for (int i = 0; i < nums.length; i++) {
            // 取出一个数字
            int num = nums[i];

            // 创建新的数字数组,删除当前数字
            int[] newNums = new int[nums.length - 1];
            for (int j = 0; j < i; j++) {
                newNums[j] = nums[j];
            }
            for (int j = i + 1; j < nums.length; j++) {
                newNums[j - 1] = nums[j];
            }

            // 递归调用函数,传递更新后的数字数组和结果字符串
            generatePermutations(newNums, current + num, result, k);

            // 如果结果列表长度等于k,直接返回
            if (result.size() == k) {
                return;
            }
        }
    }
}

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869

Python

n = int(input())
k = int(input())


if n == 1:
    print("1")
    exit()

nums = [i+1 for i in range(n)]
result = []

def generatePermutations(nums, current, result, k):
    if len(nums) == 0:
        result.append(current)
        return

    for i in range(len(nums)):
        num = nums[i]
        newNums = nums[:i] + nums[i+1:]
        generatePermutations(newNums, current + str(num), result, k)

        if len(result) == k:
            return

generatePermutations(nums, "", result, k)

result.sort()
print(result[k-1])

1234567891011121314151617181920212223242526272829

JavaScript

const readline = require('readline');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.on('line', (n) => {
  rl.on('line', (k) => {
    // 如果 n 等于 1,则直接输出 1 并结束程序
    if (n == 1) {
      console.log("1");
      rl.close();
      return;
    }

    // 初始化 nums 数组,存储 1 到 n 的整数
    let nums = [];
    for (let i = 0; i < n; i++) {
      nums.push(i + 1);
    }

    // 初始化结果列表
    let result = [];

    // 递归函数,用于生成所有排列
    generatePermutations(nums, "", result, k);

    // 对结果列表进行排序
    result.sort();

    // 输出第k个排列
    console.log(result[k - 1]);

    rl.close();
  });
});

function generatePermutations(nums, current, result, k) {
  // 如果数字数组为空,将当前结果添加到结果列表中
  if (nums.length === 0) {
    result.push(current);
    return;
  }

  // 遍历当前数字数组
  for (let i = 0; i < nums.length; i++) {
    // 取出一个数字
    let num = nums[i];

    // 创建新的数字数组,删除当前数字
    let newNums = nums.slice(0, i).concat(nums.slice(i + 1));

    // 递归调用函数,传递更新后的数字数组和结果字符串
    generatePermutations(newNums, current + num, result, k);

    // 如果结果列表长度等于k,直接返回
    if (result.length === k) {
      return;
    }
  }
}


12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364

C++

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

void generatePermutations(vector<int>& nums, string current, vector<string>& result, int k);

int main() {
    int n, k;
    vector<string> lines;
    cin >> n >> k;

    if (n == 1) {
        cout << "1" << endl;
        return 0;
    }

    vector<int> nums(n);
    for (int i = 0; i < n; i++) {
        nums[i] = i + 1;
    }

    vector<string> result;
    generatePermutations(nums, "", result, k);

    sort(result.begin(), result.end());

    cout << result[k - 1] << endl;

    return 0;
}

void generatePermutations(vector<int>& nums, string current, vector<string>& result, int k) {
    if (nums.empty()) {
        result.push_back(current);
        return;
    }

    for (int i = 0; i < nums.size(); i++) {
        int num = nums[i];
        vector<int> newNums(nums.size() - 1);
        copy(nums.begin(), nums.begin() + i, newNums.begin());
        copy(nums.begin() + i + 1, nums.end(), newNums.begin() + i);

        generatePermutations(newNums, current + to_string(num), result, k);

        if (result.size() == k) {
            return;
        }
    }
}

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152

C语言

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 生成排列的递归函数
void generatePermutations(int* nums, int numsSize, char* current, char** result, int* resultSize, int k) {
    // 如果数字数组为空,将当前结果添加到结果列表中
    if (numsSize == 0) {
        result[*resultSize] = (char*)malloc(strlen(current) + 1);
        strcpy(result[*resultSize], current);
        (*resultSize)++;
        return;
    }

    // 遍历当前数字数组
    for (int i = 0; i < numsSize; i++) {
        // 取出一个数字
        int num = nums[i];

        // 创建新的数字数组,删除当前数字
        int* newNums = (int*)malloc((numsSize - 1) * sizeof(int));
        for (int j = 0; j < i; j++) {
            newNums[j] = nums[j];
        }
        for (int j = i + 1; j < numsSize; j++) {
            newNums[j - 1] = nums[j];
        }

        // 更新结果字符串
        int newCurrentLen = strlen(current) + 10; // 分配足够大的空间
        char *newCurrent = (char*)malloc(newCurrentLen * sizeof(char));
        snprintf(newCurrent, newCurrentLen, "%s%d", current, num);

        // 递归调用函数,传递更新后的数字数组和结果字符串
        generatePermutations(newNums, numsSize - 1, newCurrent, result, resultSize, k);

        // 如果结果列表长度等于k,直接返回
        if (*resultSize == k) {
            free(newNums);
            free(newCurrent); // 避免内存泄漏
            return;
        }

        // 释放内存
        free(newNums);
        free(newCurrent); // 每次循环后释放newCurrent
    }
}

int compareStrings(const void* a, const void* b) {
    return strcmp(*(const char**)a, *(const char**)b);
}

int main() {
    int n, k;

    // 读取 n 和 k
    scanf("%d %d", &n, &k);

    // 如果 n 等于 1,则直接输出 1 并结束程序
    if (n == 1) {
        printf("1\n");
        return 0;
    }

    // 初始化 nums 数组,存储 1 到 n 的整数
    int* nums = (int*)malloc(n * sizeof(int));
    for (int i = 0; i < n; i++) {
        nums[i] = i + 1;
    }

    // 初始化结果列表
    char** result = (char**)malloc(100000000 * sizeof(char*));   
    int resultSize = 0;

    // 调用递归函数生成所有排列
    char current[100] = "";  // 初始的结果字符串为空
    generatePermutations(nums, n, current, result, &resultSize, k);

    // 对结果列表进行排序
    qsort(result, resultSize, sizeof(char*), compareStrings);

    // 输出第 k 个排列
    printf("%s\n", result[k - 1]);

    // 释放内存
    for (int i = 0; i < resultSize; i++) {
        free(result[i]);
    }
    free(result);
    free(nums);

    return 0;
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394

不用递归,用全排列

核心解题思路是基于康托展开(Cantor Expansion)原理来解决排列组合问题。康托展开是一种将排列转换为字典序数(第几个排列)的方法,反之也可以用来根据字典序数反向推导出具体的排列。

解题思路
  1. 理解排列的字典序:对于给定的整数 nk,题目要求找到由 [1, 2, ..., n] 组成的所有排列中按字典序排列的第 k 个排列。字典序排列是将排列按数值大小进行排序。

  2. 分解问题:将排列问题分解为一系列位置选择的问题:

    • 首先确定排列的第一个数字,然后确定剩下数字的排列。
    • 通过除以某个数字的阶乘,可以找到这一位上的数字索引,接着更新 k 值并继续进行下一位的选择。
  3. 计算阶乘:使用阶乘来计算某个位置上的数字有多少种可能性。

    • 对于长度为 n 的数组,第一个数字确定后,剩下的 n-1 个数字有 (n-1)! 种排列方式。
    • 例如,对于 [1, 2, 3],如果第一个数字是 1,那么剩余 [2, 3] 可以有 2! = 2 种排列。
  4. 确定每一位数字:通过计算 (k-1) / (n-1)! 来确定第一个数字的位置索引 index,然后从数字列表中删除已经选择的数字,并调整 kk % (n-1)!,继续下一位的选择。

  5. 重复过程:这个过程从左到右一位一位确定,每一步都使用上述计算方法,直到所有位都确定。

康托展开原理解析

以下通过一个例子详细讲解康托展开的原理:

例子:判断数字2143在集合{1, 2, 3, 4}的全排列中是第几大的排列?

求解过程:

集合{1, 2, 3, 4}共有4个元素,因此总共有 4 ! = 24 4! = 24 4!=24 种排列方式。要计算2143在这些排列中所处的具体位置,我们可以通过以下步骤进行:

  1. 计算首位小于2的排列数

    • 比2小的数字只有1。
    • 剩余的三个数字有 3 ! = 6 3! = 6 3!=6 种排列方式。
    • 因此,这部分排列的数量为 1 × 3 ! = 6 1 \times 3! = 6 1×3!=6。
  2. 计算首位为2、第二位小于1的排列数

    • 第二位比1小的数字不存在。
    • 因此,这部分排列的数量为 0 × 2 ! = 0 0 \times 2! = 0 0×2!=0。
  3. 计算前两位为21、第三位小于4的排列数

    • 第三位比4小的数字只有3。
    • 剩余的一个数字有 1 ! = 1 1! = 1 1!=1 种排列方式。
    • 因此,这部分排列的数量为 1 × 1 ! = 1 1 \times 1! = 1 1×1!=1。
  4. 计算前三位为214、第四位小于3的排列数

    • 第四位比3小的数字不存在。
    • 因此,这部分排列的数量为 0 × 0 ! = 0 0 \times 0! = 0 0×0!=0。
结果计算:

将以上各部分的结果相加,即可得到2143在全排列中的位置:

1 × 3 ! + 0 × 2 ! + 1 × 1 ! + 0 × 0 ! = 7 1 \times 3! + 0 \times 2! + 1 \times 1! + 0 \times 0! = 7 1×3!+0×2!+1×1!+0×0!=7

所以2143是第8大的排列。

康托展开公式

通过上述例子,我们可以推导出康托展开的通用公式:

X = a [ n ] × ( n − 1 ) ! + a [ n − 1 ] × ( n − 2 ) ! + ⋯ + a [ i ] × ( i − 1 ) ! + ⋯ + a [ 2 ] × 1 ! + a [ 1 ] × 0 ! X = a[n] \times (n-1)! + a[n-1] \times (n-2)! + \dots + a[i] \times (i-1)! + \dots + a[2] \times 1! + a[1] \times 0! X=a[n]×(n−1)!+a[n−1]×(n−2)!+⋯+a[i]×(i−1)!+⋯+a[2]×1!+a[1]×0!

其中, a [ i ] a[i] a[i]表示原数第 i i i 位在当前未出现的元素中排在第几位(从0开始计数),并且满足 0 ≤ a [ i ] < i 0 \leq a[i] < i 0≤a[i]<i( 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n)。

康托逆展开

康托展开的逆过程称为康托逆展开,即对于某个集合的全排列,输入一个数字 k k k,返回对应的第 k k k 大排列。

Java

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static String getPermutation(int n, int k) {
        // 初始化数字列表和阶乘表
        List<Integer> numbers = new ArrayList<>();
        int[] factorial = new int[n + 1];
        
        // 填充1到n的数字
        for (int i = 1; i <= n; i++) {
            numbers.add(i);
        }
        
        // 初始化阶乘表,factorial[0] = 1
        factorial[0] = 1;
        for (int i = 1; i <= n; i++) {
            factorial[i] = factorial[i - 1] * i;
        }
        
        // 调整k到0索引
        k--;
        StringBuilder result = new StringBuilder();
        
        // 从大到小确定每一位
        for (int i = n; i > 0; i--) {
            // 计算当前位数字索引
            int index = k / factorial[i - 1];
            result.append(numbers.get(index));
            
            // 移除已经选择的数字
            numbers.remove(index);
            
            // 更新k值
            k %= factorial[i - 1];
        }
        
        return result.toString();
    }

    public static void main(String[] args) {
        java.util.Scanner scanner = new java.util.Scanner(System.in);
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        System.out.println(getPermutation(n, k));
    }
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647

Python

import math

def get_permutation(n, k):
    # 初始化数字列表和阶乘表
    numbers = list(range(1, n+1))
    factorial = [1] * (n+1)
    
    # 预先计算所有阶乘值
    for i in range(2, n+1):
        factorial[i] = factorial[i-1] * i
    
    # 调整k到0索引
    k -= 1
    result = ""
    
    # 从大到小确定每一位
    for i in range(n, 0, -1):
        # 计算当前位数字索引
        index = k // factorial[i-1]
        result += str(numbers[index])
        
      
        
        # 更新k值
        k %= factorial[i-1]
    
    return result

 
n = int(input())
k = int(input())
print(get_permutation(n, k))
1234567891011121314151617181920212223242526272829303132

JavaScript

function getPermutation(n, k) {
    // 初始化数字列表和阶乘表
    let numbers = Array.from({ length: n }, (_, i) => i + 1);
    let factorial = new Array(n + 1).fill(1);

    // 预先计算所有阶乘值
    for (let i = 2; i <= n; i++) {
        factorial[i] = factorial[i - 1] * i;
    }

    // 调整k到0索引
    k--;
    let result = '';

    // 从大到小确定每一位
    for (let i = n; i > 0; i--) {
        // 计算当前位数字索引
        let index = Math.floor(k / factorial[i - 1]);
        result += numbers[index];

        // 移除已经选择的数字
        numbers.splice(index, 1);

        // 更新k值
        k %= factorial[i - 1];
    }

    return result;
}

// 示例用法
const readline = require('readline').createInterface({
    input: process.stdin,
    output: process.stdout
});

readline.on('line', n => {
    readline.on('line', k => {
        console.log(getPermutation(parseInt(n), parseInt(k)));
        readline.close();
    });
});
123456789101112131415161718192021222324252627282930313233343536373839404142

C++

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

string getPermutation(int n, int k) {
    // 初始化数字列表和阶乘表
    vector<int> numbers;
    vector<int> factorial(n + 1, 1);

    // 填充1到n的数字
    for (int i = 1; i <= n; i++) {
        numbers.push_back(i);
    }

    // 预先计算所有阶乘值
    for (int i = 2; i <= n; i++) {
        factorial[i] = factorial[i - 1] * i;
    }

    // 调整k到0索引
    k--;
    string result;

    // 从大到小确定每一位
    for (int i = n; i > 0; i--) {
        // 计算当前位数字索引
        int index = k / factorial[i - 1];
        result += to_string(numbers[index]);

        // 移除已经选择的数字
        numbers.erase(numbers.begin() + index);

        // 更新k值
        k %= factorial[i - 1];
    }

    return result;
}

int main() {
    int n, k;
    cin >> n >> k;
    cout << getPermutation(n, k) << endl;
    return 0;
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445

C语言

#include <stdio.h>
#include <stdlib.h>

void getPermutation(int n, int k, char* result) {
    // 初始化数字列表和阶乘表
    int* numbers = (int*)malloc(n * sizeof(int));
    int* factorial = (int*)malloc((n + 1) * sizeof(int));

    // 填充1到n的数字
    for (int i = 0; i < n; i++) {
        numbers[i] = i + 1;
    }

    // 初始化阶乘表
    factorial[0] = 1;
    for (int i = 1; i <= n; i++) {
        factorial[i] = factorial[i - 1] * i;
    }

    // 调整k到0索引
    k--;
    int index, pos = 0;

    // 从大到小确定每一位
    for (int i = n; i > 0; i--) {
        // 计算当前位数字索引
        index = k / factorial[i - 1];
        result[pos++] = numbers[index] + '0';  // 转换为字符保存

        // 移除已经选择的数字
        for (int j = index; j < n - 1; j++) {
            numbers[j] = numbers[j + 1];
        }

        // 更新k值
        k %= factorial[i - 1];
    }
    result[pos] = '\0';  // 添加字符串结束符

    // 释放动态分配的内存
    free(numbers);
    free(factorial);
}

int main() {
    int n, k;
    scanf("%d %d", &n, &k);
    char result[10];  // 假设n最大为9
    getPermutation(n, k, result);
    printf("%s\n", result);
    return 0;
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
<think>好的,我现在需要解决用户关于华为OD机考中“商品前K个高频方案”的真及解答的问。首先,用户之前的问是关于恰好花费K元的购买方案总数,现在转向了前K个高频方案,可能是需要找出出现次数最多的前K种方案。需要明确问的具体要求。首先,我需要确定用户的问具体是什么。根据用户提到的“商品前K个高频方案”,可能是指给定一组商品购买记录,统计每种购买方案出现的频率,然后找出出现次数最多的前K种方案。或者,可能是在所有可能的购买方案中,找出金额最大的前K种方案,或者某种特定条件下的前K个方案。需要结合华为OD机考的常见型来推测。参考之前的对话,用户之前的问是关于完全背包或0-1背包的恰好花费K元的方案数,现在转向高频方案,可能目发生了变化。例如,可能需要找出所有可能的购买组合,然后按出现频率或某种条件排序,取前K个。或者,目可能涉及到组合方案中的前K个最小或最大的方案,比如金额最小的前K种方案。接下来,我需要查找华为OD机考相关的真,特别是涉及商品和K个方案的目。根据用户提供的引用内容,引用[4]提到华为OD机考涉及动态规划、回溯、贪心等算法,可能相关目属于这些类别。例如,动态规划生成所有可能的方案,然后取前K个,或者使用优先队列来维护前K个高频或最小/大的方案。假设目类似于:给定商品价格数组,找出所有能组成总金额的购买方案,并按金额升序排列,输出前K个方案。或者,统计每个方案的出现次数,输出频率最高的前K个。但根据用户之前的例子,输出的是方案数,可能现在的目需要具体输出方案本身,并按某种顺序取前K个。例如,可能的目描述是:给定商品价格数组prices和目标金额K,找出所有恰好花费K元的购买方案,并按字典序输出前K个方案。或者,输出出现次数最多的前K种方案(但需要购买记录的数据,目可能没有给出,所以更可能是前者)。需要进一步析可能的目结构。例如,用户之前的问输出是4种方案,现在可能需要输出前K个,比如当K=2时,输出前两种方案,如字典序最小的两个。或者,目可能要求输出所有可能的方案,并按某种规则排序后取前K个。 在解法方面,可能需要先生成所有可能的方案,然后进行排序,再取前K个。生成方案可以使用回溯法,记录所有满足总金额等于目标的情况。然后对这些方案进行排序,比如按商品数量升序,或者按字典序排列,然后输出前K个。例如,输入为prices=[1,2,5],K=5,生成所有恰好5元的方案,如[1,1,1,1,1],[1,1,1,2],[1,2,2], [5]。然后按字典序排列,可能得到顺序为[1,1,1,1,1], [1,1,1,2],[1,2,2],[5]。此时,若要求前K=2个方案,输出这两个。 因此,解步骤可能包括:1.使用回溯法生成所有可能的购买方案,确保总金额等于目标K。 2.对生成的方案进行排序(按字典序、长度或其他条件)。 3.取前K个方案作为结果。 需要注意去重和剪枝,例如,当商品可以重复购买时,不同的顺序可能被视为同一方案(如[1,2]和[2,1]视为相同),此时需要避免重复计数。或者在回溯时控制顺序,比如只允许非递减顺序添加商品,这样生成的方案自然不重复,且有序。 例如,在回溯时,每次只能选择当前商品及之后的商品,这样可以避免重复组合。例如,先选1,然后下一层只能选1或更大的商品,这样生成的方案是排序后的,避免重复。 代码实现方面,可以使用回溯,并在递归时传递起始索引,确保每次选择商品不回头,从而生成唯一的组合方式。同时,记录路径,当路径总和等于K时,保存该路径。 然后,将所有符合条件的路径进行排序,取前K个。需要注意效率问,当目标K较大时,组合数可能很多,需要剪枝优化。 例如,在回溯过程中,如果当前路径的总和已经超过K,可以提前终止该支的递归。此外,排序可能需要在生成所有方案后进行,但若K较小,可能可以边生成边维护一个优先队列,只保留前K个方案,以减少内存消耗。 综上,可能的解法是回溯剪枝生成所有有效方案,排序后取前K个。接下来需要验证这个思路是否符合华为OD的真,并给出相应的代码示例。同时,需要参考用户提供的引用内容,尤其是引用[4]提到的动态规划、回溯等考点,确保解法符合华为OD的常见型。例如,引用[4]中提到的动态规划可能用于生成方案数,但输出具体方案可能需要回溯。最后,需要确保回答的结构清晰,包含问描述、输入输出样例、解思路、代码实现,以及相关考点和问,符合用户之前的提问格式。同时,按照要求使用LaTeX格式的数学表达式,引用相关段落,并生成相关问。</think>### 华为OD机考“商品前K个高频方案”真解析 --- #### 问描述(根据引用[4]动态规划与回溯考点推测) 给定商品价格数组$prices$和目标金额$K$,要求输出**恰好花费$K$元**的所有购买方案中,按**字典序升序排列**后的**前$K$个方案**。每个商品可重复购买(完全背包问变种)[^4]。 **输入样例** ``` 5 # 目标金额K=5元 [1,2,5] # 商品价格数组 3 # 要求输出前3个方案 ``` **输出样例** ``` [[1,1,1,1,1], [1,1,1,2], [1,2,2]] # 字典序最小的前3个方案 ``` --- ### 解思路与代码实现 #### 方法一:回溯剪枝 + 字典序排序 1. **回溯生成所有有效方案**:通过限制选择顺序(非递减选择商品)避免重复方案。 2. **字典序排序**:对生成的方案按字典序排序后取前$K$个。 3. **剪枝优化**:当路径累计金额超过$K$时提前终止递归。 ```python def find_k_plans(prices, K, top_k): prices.sort() # 确保字典序生成 res = [] def backtrack(start, path, current_sum): if current_sum == K: res.append(path.copy()) return for i in range(start, len(prices)): price = prices[i] if current_sum + price > K: continue # 剪枝:金额超过则跳过 path.append(price) backtrack(i, path, current_sum + price) # 允许重复选商品 path.pop() backtrack(0, [], 0) res.sort() # 按字典序排序 return res[:top_k] if top_k <= len(res) else res # 测试样例 print(find_k_plans([1,2,5], 5, 3)) # 输出[[1,1,1,1,1], [1,1,1,2], [1,2,2]] ``` --- #### 关键考点解析 1. **字典序控制**:通过先对$prices$排序,并在回溯时按非递减顺序选择商品,保证生成的方案自然有序[^4]。 2. **剪枝优化**:时间复杂度由$O(2^N)$降低到$O(\text{valid\_combinations})$。 3. **去重处理**:限制每次选择的起始位置,避免生成重复方案(如`[1,2]`和`[2,1]`视为同一方案)。 --- ### 相关问 1. 如何优化算法以处理较大的$K$值(如$K=1000$)? 2. 如果要求输出金额最小的前$K$个方案(而非字典序),应如何调整排序逻辑? 3. 当商品数量较多时(如$prices$长度为50),如何避免内存溢出? 4. 如何用动态规划记录具体方案(而非仅方案数)? 5. 如果商品只能购买一次(0-1背包),算法需要如何修改? --- [^4]: 参考华为OD机考动态规划与回溯考点说明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值