# 【LeetCode刷題】【演算法學習筆記】977. Squares of a Sorted Array * 學習時間:2025/01/30 (Fir.) * **題目連結(美服):** [977. Squares of a Sorted Array](https://leetcode.com/problems/remove-element/description/) * **題目連結(國服):**[977.有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array/description/) * **兄弟題:** * **題目標籤:** ==陣列== ==雙指針== ==排序== ### A. 題目 --- >Given an integer array nums sorted in non-decreasing order, return an array of the squares of each number sorted in non-decreasing order. >Example 1: >Input: nums = [-4,-1,0,3,10] Output: [0,1,9,16,100] Explanation: After squaring, the array becomes [16,1,0,9,100]. After sorting, it becomes [0,1,9,16,100]. >Example 2: Input: nums = [-7,-3,2,3,11] Output: [4,9,9,49,121] ### B. 題意(中文) --- >给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。 >示例 1: 输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100] >示例 2: 输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]元素和 nums 的大小并不重要。 ### C. 參考程式碼 --- :::spoiler Thinking(思路) reference: [力扣官方题解](https://leetcode.cn/problems/squares-of-a-sorted-array/solutions/447736/you-xu-shu-zu-de-ping-fang-by-leetcode-solution/) [灵茶山艾府](https://leetcode.cn/problems/squares-of-a-sorted-array/solutions/2806253/xiang-xiang-shuang-zhi-zhen-cong-da-dao-blda6/) #### 官方題解 * 寫法一:將陣列 nums 中的數平方後直接排序。 * 寫法二:雙指針 1. **為利用到陣列升序條件** * 因為平方後可能會變成無序 * 所以使用 **neg** 區分元素正負值 * nums[0] 到 nums[neg] 為負數 ☞ 平方後會遞減 * nums[neg] 到 nums[n-1] 為正數 ☞ 平方後會遞增 2. **排序算法思路** ➡︎ ==雙指針== * 指針指向 **neg** 和 非負數 **neg+1** * 每次選擇較小數值加入陣列 * 剩餘部分直接加入結果 3. 範例: ![截圖 2025-02-04 晚上7.07.27](https://hackmd.io/_uploads/r18fBd1Kye.png) * 寫法三:雙指針 * 一個指向位置 0,一個指向位置 n-1 * 比較兩指針數值,選擇較大的數值 * **逆序**放入陣列 ☞ 因為平方後會兩端大,中間小 * 例如:[-4, -2, 0, 3, 5],平方:[16, 4, 0, 9, 25] --- #### 靈神題解 * 寫法一:陣列分成負數 和 非負數 * 算法實現 💡 **雙指針從陣列兩端走向中間 ➡︎ 比較大小並合併** * 初始化 ➡︎ 左指針:i = 0; 右指針:j = n-1; 新陣列:ans 下標為 p = n-1 (**逆序**放入陣列) * 平方 ➡︎ nums[i]^2 nums[j]^2 * 大小比較 ➡︎ 大的填入 ans[p],直到 p = -1 * 寫法二: * 算法實現 💡 **比较 −nums[i] 和 nums[j] 的大小** * 如果 nums 中的元素**均為負數** -nums[i] > 0 > num[j] 恆成立 ➡︎ [-7, -5, -3, -1] * 如果 nums 中的元素**均為非負數** -nums[i] <= 0 <= num[j] ➡︎ [7, 5, 3, 1, 0] * 如果 nums[i] < 0, nums[j] >= 0, 比較結果等價於 nums[i]^2, nums[j]^2 ➡︎ [-7, -5, -2, 0, 3, 1] ::: :::spoiler Note(筆記) **複雜度** 1. 平方後直接排序 * Time complexity: **O(nlogn)** ➡︎ n 為陣列長度 * Space complexity: **O(logn)** ➡︎ 儲存答案的陣列以外,我们需要 O(logn) 的 Stack Space 來排序。 2. 雙指針 * Time complexity:**O(n)** ➡︎ n 為陣列長度 * Space complexity: **O(1)** ➡︎ 直接在原陣列中修改(如就地排序),將空間複雜度優化到 O(1),返回值不記錄。 * 補充:若使用了额外的空間儲存結果,Space complexity 將上升至 O(n) ::: :::spoiler 官方題解一 ```python= class Solution: def sortedSquares(self, nums: List[int]) -> List[int]: # 陣列長度 n = len(nums) # 儲存最後一個負數的索引位置 neg = -1 # enumerate: 拜訪 nums 同時取得索引 (i) 和對應的數值 (num) for i, num in enumerate(nums): if num < 0: # 如果 num 是負數,就更新 neg(找最後一個負數的索引) neg = i # index else: break ans = list() # i: 最後一個負數 index; j: 第一個非負數 index i, j = neg, neg + 1 # 每次選擇較小數值加入陣列 while i >= 0 or j < n: # 只要 i 或 j 還沒超出邊界,就繼續執行 # 處理邊界條件 if i < 0: # 代表負數部分已經遍歷完 ,指針直接移動到 j,處理剩下的另一半 ans.append(nums[j] * nums[j]) j += 1 elif j == n: ans.append(nums[i] * nums[i]) i -= 1 # 比較 nums[i]² 和 nums[j]²,選擇較小的加入 ans,並移動對應指針 elif nums[i] * nums[i] < nums[j] * nums[j]: ans.append(nums[i] * nums[i]) i -= 1 else: ans.append(nums[j] * nums[j]) j += 1 return ans ``` ::: :::spoiler 官方題解二 ```python= class Solution: # 指针分别指向位置 0 和 n−1 def sortedSquares(self, nums: List[int]) -> List[int]: # 陣列長度 n = len(nums) ans = [0] * n i, j, pos = 0, n-1, n-1 # pos 倒序由大到小儲存答案 while i <= j: # 比較 nums[i]² 和 nums[j]²,選擇較大的加入 ans,並移動對應指針 if nums[i] * nums[i] > nums[j] * nums[j]: ans[pos] = nums[i] * nums[i] i += 1 else: ans[pos] = nums[j] * nums[j] j -= 1 pos -= 1 return ans ``` ::: :::spoiler 靈神題解一 * reference: https://leetcode.cn/problems/squares-of-a-sorted-array/solutions/2806253/xiang-xiang-shuang-zhi-zhen-cong-da-dao-blda6/ * 概念:藉雙指針,從兩端開始,向中間合併。 ➡︎ 避免還需要計算要從中間哪個地方開始 * 程式:初始化空陣列 ans 和 其下標,雙指針 ➡︎ 計算兩端平方 ➡︎ 比較:選擇較大值填入 ans,直到陣列都填入數值 ```python= from typing import List # 导入 List(否则 Python 解释器会报 NameError: name 'List' is not defined) class Solution: # 指针分别指向位置 0 和 n−1 def sortedSquares(self, nums: List[int]) -> List[int]: # 陣列長度 n = len(nums) ans = [0] * n i, j = 0, n - 1 # 左右指針初始化 # 答案陣列計算 for p in range(n - 1, -1, -1): # ans初始位置:n-1, 向左移:-1, 直到索引為0 left = nums[i] * nums[i] # 左指針平方值 right = nums[j] * nums[j] # 右指針平方值 # 比較雙指針大小 if left > right: ans[p] = left i += 1 else: ans[p] = right j -= 1 # 修正:右指針應該向左移 return ans ``` ::: :::spoiler ⭐️靈神題解二 * reference: https://leetcode.cn/problems/squares-of-a-sorted-array/solutions/2806253/xiang-xiang-shuang-zhi-zhen-cong-da-dao-blda6/ * 思路:先將左指針加上負號處理,在比較左右指針大小 * 優點:每次循環只要計算一次乘法 * 击败:97.81% ```python= from typing import List # 导入 List(否则 Python 解释器会报 NameError: name 'List' is not defined) class Solution: # 指针分别指向位置 0 和 n−1 def sortedSquares(self, nums: List[int]) -> List[int]: n = len(nums) ans = [0] * n i, j = 0, n-1 # 初始化左右指針: i, j # 左右指針數值比較,選擇較大平方,反序填入 ans # 處理答案陣列 for p in range(n-1, -1, -1): # 初始化 p ans下標 x, y = -nums[i], nums[j] # 比較左右指針大小 if x > y: ans[p] = nums[i] * nums[i] i += 1 else: ans[p] = nums[j] * nums[j] j -= 1 return ans ``` :::