力扣解题-[3379]转换数组

4 阅读5分钟

力扣解题-[3379]转换数组

题目: 给你一个整数数组 nums,它表示一个循环数组。请你遵循以下规则创建一个大小 相同 的新数组 result :

对于每个下标 i(其中 0 <= i < nums.length),独立执行以下操作: 如果 nums[i] > 0:从下标 i 开始,向 右 移动 nums[i] 步,在循环数组中落脚的下标对应的值赋给 result[i]。 如果 nums[i] < 0:从下标 i 开始,向 左 移动 abs(nums[i]) 步,在循环数组中落脚的下标对应的值赋给 result[i]。 如果 nums[i] == 0:将 nums[i] 的值赋给 result[i]。 返回新数组 result。

注意:由于 nums 是循环数组,向右移动超过最后一个元素时将回到开头,向左移动超过第一个元素时将回到末尾。

示例 1:

输入: nums = [3,-2,1,1]

输出: [1,1,1,3]

解释:

对于 nums[0] 等于 3,向右移动 3 步到 nums[3],因此 result[0] 为 1。 对于 nums[1] 等于 -2,向左移动 2 步到 nums[3],因此 result[1] 为 1。 对于 nums[2] 等于 1,向右移动 1 步到 nums[3],因此 result[2] 为 1。 对于 nums[3] 等于 1,向右移动 1 步到 nums[0],因此 result[3] 为 3。 示例 2:

输入: nums = [-1,4,-1]

输出: [-1,-1,4]

解释:

对于 nums[0] 等于 -1,向左移动 1 步到 nums[2],因此 result[0] 为 -1。 对于 nums[1] 等于 4,向右移动 4 步到 nums[2],因此 result[1] 为 -1。 对于 nums[2] 等于 -1,向左移动 1 步到 nums[1],因此 result[2] 为 4。 提示:

1 <= nums.length <= 100 -100 <= nums[i] <= 100 Related Topics 数组 模拟


第一次解答

解题思路

核心方法:模拟循环移动过程 + 逐步调整目标索引,直接贴合题目描述的移动规则,逻辑直观易懂,无需复杂数学运算。

具体步骤:

  1. 首先获取输入数组nums的长度length,并初始化一个与nums长度相同的结果数组result,用于存储最终转换结果。
  2. 遍历输入数组nums的每个下标i,针对每个下标执行独立的转换操作: a. 获取当前下标i对应的数组值value = nums[i]。 b. 计算初始目标索引targetNum = i + value(核心逻辑:向右移动对应value为正,索引直接累加;向左移动对应value为负,索引直接递减,无需额外区分正负,统一用加法即可贴合题目移动规则)。 c. 处理目标索引超出数组上限的情况(对应向右移动超出末尾回到开头):通过while循环,若targetNum >= length,则不断减去数组长度length,直到targetNum落入有效索引范围[0, length)。 d. 处理目标索引低于数组下限的情况(对应向左移动超出开头回到末尾):通过while循环,若targetNum < 0,则不断加上数组长度length,直到targetNum落入有效索引范围[0, length)。 e. 此时targetNum为合法的循环落脚下标,将nums[targetNum]赋值给result[i],完成当前下标的转换。
  3. 遍历完成后,返回结果数组result

执行耗时:1 ms,击败了100.00% 的Java用户 内存消耗:46 MB,击败了40.00% 的Java用户

public int[] constructTransformedArray(int[] nums) {
        int length = nums.length;
        int[] result = new int[length];
        for (int i = 0; i < length; i++) {
            int value = nums[i];
            int targetNum = i + value;
            while (targetNum >= length) {
                targetNum = targetNum-length;
            }
            while (targetNum < 0) {
                targetNum = targetNum + length;
            }
            result[i]=nums[targetNum];
        }
        return result;
    }

第二次解答

解题思路

核心方法:利用取模运算直接求解有效循环索引,借助循环数组的数学特性,替代第一次解答中的循环调整,简化索引计算逻辑,同时优化内存消耗。

具体步骤:

  1. 首先获取输入数组nums的长度length,并初始化一个与nums长度相同的结果数组result,用于存储最终转换结果。
  2. 遍历输入数组nums的每个下标i,针对每个下标执行独立的转换操作: a. 计算初始目标索引并进行第一次取模:newIndex = (i + nums[i]) % length(取模运算的核心特性:可快速得到一个数除以另一个数的余数,天然适配循环数组的索引循环特性,替代多次加减数组长度的循环操作)。 b. 处理负余数情况(当i + nums[i]为负数时,取模结果可能为负,超出有效索引范围):若newIndex < 0,则给newIndex加上数组长度length,将其转换为正的有效索引。 c. 额外执行一次取模校验newIndex %= length:确保经过上一步调整后的索引仍严格落在[0, length)范围内,避免极端情况(如newIndex等于length)导致的数组越界。 d. 此时newIndex为合法的循环落脚下标,将nums[newIndex]赋值给result[i],完成当前下标的转换。
  3. 遍历完成后,返回结果数组result

核心优化点说明:

  • 取模运算替代while循环调整索引,减少了循环迭代的开销,逻辑更简洁高效。
  • 取模运算直接贴合循环数组的数学本质,无需分步模拟“超出边界-回绕”的过程,代码可读性和健壮性更强。

执行耗时:1 ms,击败了100.00% 的Java用户 内存消耗:45.9 MB,击败了72.73% 的Java用户

public int[] constructTransformedArray(int[] nums) {
        int length = nums.length;
        int[] result = new int[length];
        for (int i = 0; i < length; i++) {
            // 计算目标索引:从 i 出发,移动 nums[i] 步(可正可负),循环
            int newIndex = (i + nums[i]) % length;
            if (newIndex < 0) {
                newIndex += length; // 转为正索引
            }
            newIndex %= length; // 确保在 [0, length)
            result[i] = nums[newIndex];
        }
        return result;
    }

总结

  1. 两次解答均贴合题目「循环数组移动」的核心要求,最终执行耗时一致(1ms),均能高效解决问题。
  2. 第一次解答是「模拟移动 + 循环调整索引」,逻辑直观,贴合题目描述,适合新手理解循环数组的回绕规则。
  3. 第二次解答是「取模运算 + 负索引校正」,利用数学特性简化代码,减少内存消耗,是更优的工程实现方案。