[LeetCode]C语言-Next Permutation-程序优化之路

本文详细介绍了如何用C语言解决LeetCode中的Next Permutation问题,探讨了如何找到一个排列的下一个更大排列。文章通过实例解释了算法思路,包括当遇到递减序列时如何找到最小的大于当前元素的数进行交换,并调整为递增序列。最后,作者分享了代码优化的过程,减少了冗余的递增序列判断,从而提高了效率。

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

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place and use only constant extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.

1,2,3 → 1,3,2
3,2,1 → 1,2,3

1,1,5 → 1,5,1

首先看到这个题目,对于我这个英语废物来说多么痛苦抓狂,我硬着头皮再上网搜索才最终明白了。这道题就是求这个组合的下一个排列,下一个排列比上一个大。简单举个例子,{1,2,3}的排列依次为

1,2,3 →  1,3,2 →  2,1,3 → 2,3,1 → 3,1,2 → 3,2,1

我们从后往前看可以以发现,如果后面是一个递增序列如{3,1,2},只需将后面两个元素互换即可得{3,2,1}。如果后面为一个递减序列如{2,3,1},那就比较麻烦,因为后面两个数已经最大,只能换递减序列的前一位”2“,所以从后面的递减序列中找到最小的比“2”大的数“3”,将这两个互换位置,得到{3,2,1},这样就结束了吗?当然没有,还要将最后的序列调为递增得到结果{3,1,2}。就是这样,我们现在看一个比较复杂的例子:{5,4,7,5,3,2}来验证我们的规律。

1.首先看它的结尾是什么序列,{7,5,3,2}递减序列。

2.将其递减序列前一位“4”与递减序列中的最小的比“4”大的数“5”互换位置得{5,5,7,4,3,2}。

3.将改变后的递减序列调为递增序列的{5,5,2,3,4,7}。

我们使用这个规律实现我们的代码:

8ms

void swap(int* a, int* b) {
    int tmp = 0;
    tmp = *a;
    *a = *b;
    *b = tmp;
}
void nextPermutation(int* nums, int numsSize) {
    int i = numsSize - 1;
    int icount = 0;
    int dcount = 0;
    int head = 0;

    //判断后面为递减序列还是递增序列
    for(i = numsSize - 1; i > 0; i--) {
        if(nums[i] > nums[i-1]) {
            if(dcount > 0) {
                head = i-1;
                break;
            }
            icount++;
        }
        else {
            if(icount > 0) {
                //找到递减序列前一个元素
                head = i-1;
                break;
            }
            dcount++;
        }
    }
    //递增序列交换最后两位
    if(icount > 0) {
        swap(&nums[numsSize - 1], &nums[numsSize - 2]);
    }
    //递减序列
    if(dcount > 0) {
        //整个排列为递减
        if(dcount == numsSize - 1) {
            i = 0;
            while(i < numsSize/2){
                 swap(&nums[i], &nums[numsSize - i - 1]);
				 i++;
            }
        }
        //最后为递减序列
        else {
            //找到递减序列中最小的比前一个元素大的元素
            while(nums[head] < nums[i] && i < numsSize) {
                i++;
            }
            //交换这两个元素
            swap(&nums[i - 1], &nums[head]);
			i = head + 1;
            //将改变后的递减序列变为递增序列
			while(i < (numsSize + head - i)){
                 swap(&nums[i], &nums[numsSize + head - i]);
				 i++;
            }
        }
    }
}

运行结果:


虽然已经成功了,但是我的强迫症又犯了,每到100%就看着不舒服,于是我试着再优化一下程序,然后发现递增序列判定冗余了,因为递增我们是互换最后两位位置,我们判定递增只需判定一次就可以了,无需判定多次,最后得到我们的最后的版本。

4ms

void swap(int* a, int* b) {
    int tmp = 0;
    tmp = *a;
    *a = *b;
    *b = tmp;
}
void nextPermutation(int* nums, int numsSize) {
    int i = numsSize - 1;
    int dcount = 0;
    int head = 0;
    int end = 0;
	int j = 0;
    if(numsSize < 2) {
        return 0;
    }
    for(; i > 0; i--) {
        if(nums[i] <= nums[i-1]) {
            dcount++;
        }
        else {
            head = i - 1;
            break;
        }
    }
    if(dcount == 0) {
        swap(&nums[numsSize - 1], &nums[numsSize - 2]);
    }
    if(dcount > 0) {
        if(dcount == numsSize - 1) {
            i = 0;
            while(i < numsSize/2){
                 swap(&nums[i], &nums[numsSize - i - 1]);
				 i++;
            }
        }
        else {
            while(nums[head] < nums[i] && i < numsSize) {
                i++;
            }
            swap(&nums[i - 1], &nums[head]);
			i = head + 1;
			while(i < (numsSize + head - i)){
                 swap(&nums[i], &nums[numsSize + head - i]);
				 i++;
            }
        }
    }
}
运行结果:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值