#51 Previous Permutation

本文介绍了一种算法,用于找出给定整数序列的前一个字典序排列。该算法适用于包含重复元素的情况,并提供了一个C++实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

Given a list of integers, which denote a permutation.

Find the previous permutation in ascending order.

 Notice

The list may contains duplicate integers.

Example

For [1,3,2,3], the previous permutation is [1,2,3,3]

For [1,2,3,4], the previous permutation is [4,3,2,1]

题目思路:

这题和#51差不多,有些地方改一下就好了。

Mycode(AC = 30ms):

class Solution {
public:
    /**
     * @param nums: An array of integers
     * @return: An array of integers that's previous permuation
     */
    vector<int> previousPermuation(vector<int> &nums) {
        // write your code here
        if (nums.size() <= 1) return nums;
        
        // find the key position
        int idx = -1;
        for (int i = nums.size() - 2; i >= 0; i--) {
            if (nums[i] > nums[i + 1]) {
                idx = i;
                break;
            }
        }
        
        // if is the larget sequence, return reverse
        if (idx == -1) {
            reverse(nums.begin(), nums.end());
            return nums;
        }
        
        int second_max = nums[idx + 1], second_idx = idx + 1;
        for (int i = idx + 1; i < nums.size(); i++) {
            if (nums[i] < nums[idx] && nums[i] > second_max) {
                second_max = nums[i];
                second_idx = i;
            }
        }
        
        // swap
        swap(nums, idx, second_idx);
        
        // sort the rest numbers with decending order
        sort(nums.begin() + idx + 1, nums.end());
        reverse(nums.begin() + idx + 1, nums.end());
        
        return nums;
    }
    
    void swap(vector<int> &nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
};

在 C++ 中,标准库并没有直接提供名为 `<permutation>` 的头文件。如果你需要处理排列(permutation)相关的操作,可以使用以下方法: ### 1. **使用 `<algorithm>` 中的 `std::next_permutation` 或 `std::prev_permutation`** - 这两个函数可以生成序列的全排列或判断是否可以生成下一个排列。 - 示例: ```cpp #include <algorithm> #include <vector> #include <iostream> int main() { std::vector<int> v = {1, 2, 3}; do { for (int x : v) std::cout << x << " "; std::cout << "\n"; } while (std::next_permutation(v.begin(), v.end())); return 0; } ``` - 输出: ``` 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 ``` ### 2. **使用 `<numeric>` 中的 `std::iota` 初始化序列** - 如果你需要生成一个连续的整数序列,可以使用 `std::iota`。 - 示例: ```cpp #include <numeric> #include <vector> #include <iostream> int main() { std::vector<int> v(5); std::iota(v.begin(), v.end(), 1); // 填充 1, 2, 3, 4, 5 for (int x : v) std::cout << x << " "; return 0; } ``` ### 3. **手动实现排列生成** - 如果你需要更复杂的排列操作,可以手动实现递归或回溯算法。 - 示例(递归生成排列): ```cpp #include <vector> #include <iostream> void permute(std::vector<int>& nums, int start, std::vector<std::vector<int>>& result) { if (start == nums.size()) { result.push_back(nums); return; } for (int i = start; i < nums.size(); i++) { std::swap(nums[start], nums[i]); permute(nums, start + 1, result); std::swap(nums[start], nums[i]); // 回溯 } } int main() { std::vector<int> nums = {1, 2, 3}; std::vector<std::vector<int>> result; permute(nums, 0, result); for (const auto& perm : result) { for (int x : perm) std::cout << x << " "; std::cout << "\n"; } return 0; } ``` ### 4. **使用第三方库** - 如果你需要更高级的组合数学功能,可以考虑使用第三方库如: - **Boost.Combinatorics**(提供排列、组合等操作) - **C++ Combinatorics Library**(如 `cpp-permute`) ### 常见问题 1. **为什么没有 `<permutation>` 头文件?** - C++ 标准库没有直接提供 `<permutation>`,但 `<algorithm>` 中的 `std::next_permutation` 和 `std::prev_permutation` 可以满足基本需求。 2. **如何生成所有排列?** - 使用 `std::next_permutation` 或递归回溯方法。 3. **如何优化排列生成的性能?** - 对于大规模数据,可以考虑 Heap&#39;s algorithm(非递归实现)或并行计算。 4. **如何处理重复元素的排列?** - 使用 `std::sort` 排序后,跳过重复元素(在 `std::next_permutation` 之前检查)。 5. **是否有现成的库支持排列?** - Boost 和某些第三方库提供更高级的组合数学功能。 ### 示例代码(使用 `std::next_permutation` 生成排列) ```cpp #include <algorithm> #include <vector> #include <iostream> int main() { std::vector<int> v = {1, 2, 2}; std::sort(v.begin(), v.end()); // 排序以跳过重复排列 do { for (int x : v) std::cout << x << " "; std::cout << "\n"; } while (std::next_permutation(v.begin(), v.end())); return 0; } ``` ### 输出: ``` 1 2 2 2 1 2 2 2 1 ``` 如果你有更具体的需求(如部分排列、排列索引计算等),可以进一步说明!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值