LeeCode912. 排序数组

给你一个整数数组 nums,请你将该数组升序排列。

你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。

    示例 1:

    输入:nums = [5,2,3,1]
    输出:[1,2,3,5]
    

    示例 2:

    输入:nums = [5,1,1,2,0,0]
    输出:[0,0,1,1,2,5]
    

    提示:

    • 1 <= nums.length <= 5 * 104
    • -5 * 104 <= nums[i] <= 5 * 104

    代码:

    #include "solution.h"
    #include <algorithm>
    #include <vector>
    #include <set>
    #include <stdlib.h>
    
    static void swapeValue(int& a, int& b) {
    	int temp = a;
    	a = b;
    	b = temp;
    }
    
    static int getMiddleVal(int a, int b, int c) {
    	int arr[] = {a, b, c};
    	// 等号右边是lambda表达式,表示一个匿名函数,参数是俩个指针,返回int值。 符号 ->int 可省略,能自动推导出返回值类型
    	auto compareFuc = [](const void* p1, const void* p2) ->int {
    			return *((int*)p1) - *((int*)p2);
    		};
        // 这里c语言的qsort函数,只排序a,b,c 3个数。这里偷个懒了
    	qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), compareFuc);
    	return arr[1];
    }
    
    // 将数组这个区间分成左右两个区间,返回中间数的idx,左边区间的所有数小于idx索引处的数,右边区间的数都大于idx索引处的数
    // 为了找到这个idx,过程中可以交换一些数的值。
    static int getIdx(vector<int>& nums, int startIdx, int endIdx) { 
    	static auto flag = true; // 有很多相同数字时,超时!为解决这个问题,引入变量flag,让中间值尽量处在区域中间的某个位置
    	if (startIdx == endIdx - 1) {
    		// 相邻的
    		if (nums[endIdx] < nums[startIdx]) {
    			int temp = nums[startIdx];
    			nums[startIdx] = nums[endIdx];
    			nums[endIdx] = temp;
    		}
    		return startIdx;
    	}
    
    	// 尽量用区域中间某个值作为分界线
    	int idx = startIdx;
    	int midIdx = (startIdx + endIdx) >> 1;
    	int middleVal = getMiddleVal(nums[startIdx], nums[midIdx], nums[endIdx]);
    	int idx_ = startIdx; // 中间那个值对应的索引
    	if (nums[midIdx] == middleVal) {
    		idx_ = midIdx;
    	}
    	else if (nums[endIdx] == middleVal) {
    		idx_ = endIdx;
    	}
    	if (idx_ != idx) {
    		swapeValue(nums[idx], nums[idx_]);
    	}
    	
    	for (int i = startIdx + 1; i <= endIdx; i++) {
    		if (nums[i] < nums[idx] || (flag && nums[i] == nums[idx])) {
    			// 交换nums[i]和 nums[idx + 1]的值
    			// 交换nums[idx] 和nums[idx + 1]的值。
    			// idx值+1
    			// 这样,那个小的值就交换到前面了
    			swapeValue(nums[i], nums[idx + 1]);
    			swapeValue(nums[idx], nums[idx + 1]);
    			++idx;
    			flag = !flag;
    		}
    	}
    	return idx;
    }
    
    void qsort(vector<int>& nums, int startIdx, int endIdx) {
    	if (startIdx >= endIdx)
    		return;
    	int idx = getIdx(nums, startIdx, endIdx);
    	qsort(nums, startIdx, idx - 1);
    	qsort(nums, idx + 1, endIdx);
    }
    
    class Solution {
    public:
        vector<int> sortArray(vector<int>& nums) {
            if (nums.size() < 2) {
    	        return nums;
            }
            qsort(nums, 0, nums.size() - 1);
            return nums;
        }
    };
    
    

     测试代码:

    void testLeeCode912() { // 排序数组
    	vector<int> nums = {5, 2, 3, 1};
    	Solution* solution = new Solution();
    	solution->sortArray(nums);
    	for (auto& val : nums) {
    		std::cout << val << endl;
    	}
    	delete solution; // 回收内存
    }

    测试结果:

    ok!

    提交到LeeCode:

    ok!

    总结:总体方法是分段排序。需要将数组分为俩个区域,有中间的一个数,左边的数都小于这个数,右边的数都大于这个数,再对递归每个区域用同样方法。 但是特殊情况容易超时,比如数组是倒序的,或者数组多数数字都一样的情况,这俩种递归次数太多,然后一步步优化。

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值