Medium

题目描述

给你一个下标从 0 开始的数组 nums ,数组由若干 互不相同 的整数组成。你打算重新排列数组中的元素,使重新排列后的数组满足:每个元素都 不等于 其两个相邻元素的 平均值

更正式地,重新排列的数组应当满足这一属性:对于范围 1 <= i < nums.length - 1 中的每个 i(nums[i-1] + nums[i+1]) / 2 不等于 nums[i]

返回满足上述要求的 nums 的任一重新排列。

示例 1:

输入:nums = [1,2,3,4,5]
输出:[1,2,4,5,3]
解释:
当 i=1 时,nums[i] = 2,其相邻元素平均值是 (1+4) / 2 = 2.5
当 i=2 时,nums[i] = 4,其相邻元素平均值是 (2+5) / 2 = 3.5
当 i=3 时,nums[i] = 5,其相邻元素平均值是 (4+3) / 2 = 3.5

示例 2:

输入:nums = [6,2,0,9,7]
输出:[9,7,6,2,0]
解释:
当 i=1 时,nums[i] = 7,其相邻元素平均值是 (9+6) / 2 = 7.5
当 i=2 时,nums[i] = 6,其相邻元素平均值是 (7+2) / 2 = 4.5
当 i=3 时,nums[i] = 2,其相邻元素平均值是 (6+0) / 2 = 3

提示:

  • 3 <= nums.length <= 10^5
  • 0 <= nums[i] <= 10^5

解题思路

解题思路

这道题的关键是理解什么情况下一个数会等于其相邻两个数的平均值。如果 nums[i] = (nums[i-1] + nums[i+1]) / 2,那么说明 nums[i] 恰好位于 nums[i-1]nums[i+1] 的中间位置。

要避免这种情况,我们可以采用交替排列的策略。具体思路如下:

  1. 排序分组:将数组排序,然后将较小的一半数字和较大的一半数字分开
  2. 交替放置:将较小的数字放在奇数位置,较大的数字放在偶数位置(或相反)

这样安排的原理是:

  • 相邻的元素来自不同的组(一个较小,一个较大)
  • 由于元素互不相同且来自有序的两个部分,中间的元素不可能是两边元素的平均值

推荐解法:排序 + 交替放置,因为思路清晰,实现简单,时间复杂度最优。

另一种思路是先排序,然后将数组分成两半,交替取元素构成新数组。或者使用更直观的方法:先排序,然后按照"小-大-小-大"的模式重新排列。

代码实现

class Solution {
public:
    vector<int> rearrangeArray(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<int> result(nums.size());
        
        int mid = nums.size() / 2;
        int smallIdx = 0, largeIdx = mid;
        
        for (int i = 0; i < nums.size(); i++) {
            if (i % 2 == 0) {
                result[i] = nums[smallIdx++];
            } else {
                result[i] = nums[largeIdx++];
            }
        }
        
        return result;
    }
};
class Solution:
    def rearrangeArray(self, nums: List[int]) -> List[int]:
        nums.sort()
        result = [0] * len(nums)
        
        mid = len(nums) // 2
        small_idx, large_idx = 0, mid
        
        for i in range(len(nums)):
            if i % 2 == 0:
                result[i] = nums[small_idx]
                small_idx += 1
            else:
                result[i] = nums[large_idx]
                large_idx += 1
        
        return result
public class Solution {
    public int[] RearrangeArray(int[] nums) {
        Array.Sort(nums);
        int[] result = new int[nums.Length];
        
        int mid = nums.Length / 2;
        int smallIdx = 0, largeIdx = mid;
        
        for (int i = 0; i < nums.Length; i++) {
            if (i % 2 == 0) {
                result[i] = nums[smallIdx++];
            } else {
                result[i] = nums[largeIdx++];
            }
        }
        
        return result;
    }
}
var rearrangeArray = function(nums) {
    nums.sort((a, b) => a - b);
    const result = [];
    let left = 0, right = nums.length - 1;
    
    for (let i = 0; i < nums.length; i++) {
        if (i % 2 === 0) {
            result.push(nums[left++]);
        } else {
            result.push(nums[right--]);
        }
    }
    
    return result;
};

复杂度分析

复杂度类型
时间复杂度O(n log n)
空间复杂度O(n)

说明:

  • 时间复杂度:O(n log n) 主要来自排序操作,后续的重排列是 O(n)
  • 空间复杂度:O(n) 用于存储结果数组,排序可能需要 O(log n) 的额外空间(取决于具体实现)

相关题目