🔗 🟡 3011. Find if Array Can Be Sorted 1497

tags: Biweekly Contest 122 陣列(Array) 模擬(Simulation)

題意

給定一個下標從 00 開始的正整數陣列 numsnums

在一個操作中,如果兩個 相鄰 元素在二進位下 11 的個數 相同,那麼可以將這兩個元素交換。可以執行這個操作 任意次(包含 00 次)。

如果可以排序陣列,返回 TrueTrue,否則返回 FalseFalse

約束條件

  • 1nums.length1001 \leq \text{nums.length} \leq 100
  • 1nums[i]281 \leq \text{nums[i]} \leq 2^8

思路:分組循環 + 維護組內最大值

根據題意,只有相鄰且二進位下 11 的個數相同的元素可以交換,而若相鄰的某些元素都能交換,則在若干次操作後這些元素都可以互相交換。因此我們可以將陣列中的元素根據它們的二進位表示中 11 的個數進行分組,對於每一組組內元素,我們可以任意交換相鄰的兩個元素。

在若干次交換後必定可以使得組內元素是有序的,因此我們只需要考慮不同組之間的元素是否是有序的。為此我們需要檢查當前組內的最小值是否大於上一組的最大值,如果是則無法通過交換操作將整個陣列排序。

具體步驟如下:

  1. 使用一個指標 ii 從左向右遍歷陣列,並初始化變數 pre_mxpre\_mx1-1,用於記錄前一組的最大值。這裡使用 1-1 是因為陣列中的元素均為正整數。
  2. 對於當前指標 ii 所指向的元素 nums[i]nums[i],計算它二進位下 11 的個數 cntcnt
  3. ii 開始,不斷向右移動指標,直到遇到一個二進位下 11 的個數不等於 cntcnt 的元素為止。這樣可以遍歷完當前元素所在的組。
  4. 在遍歷該組的過程中,維護該組內的最大值 mxmx。同時檢查當前元素是否小於上一組的最大值 pre_mxpre\_mx,如果小於則說明無法通過交換操作將整個陣列排序,直接返回 FalseFalse
  5. 遍歷完當前組後,更新 pre_mxpre\_mx 為當前組的最大值 mxmx,然後繼續遍歷下一組。
  6. 如果能夠遍歷完整個陣列且沒有返回 FalseFalse,則說明可以通過交換操作將整個陣列排序,返回 TrueTrue

複雜度分析

  • 時間複雜度:O(n)O(n),其中 nn 是陣列的長度。
  • 空間複雜度:O(1)O(1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def canSortArray(self, nums: List[int]) -> bool:
n = len(nums)
i = 0
pre_mx = -1
while i < n:
mx = nums[i]
cnt = nums[i].bit_count()
while i < n and nums[i].bit_count() == cnt:
if nums[i] < pre_mx:
return False
mx = max(mx, nums[i])
i += 1
pre_mx = mx
return True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
bool canSortArray(vector<int>& nums) {
int n = nums.size(), i = 0, pre_mx = -1;
while (i < n) {
int mx = nums[i];
int cnt = __builtin_popcount(nums[i]);
while (i < n && __builtin_popcount(nums[i]) == cnt) {
if (nums[i] < pre_mx) return false;
mx = max(mx, nums[i]);
i++;
}
pre_mx = mx;
}
return true;
}
};

寫在最後

Cover photo is remixed from @吃肥皂泡泡, thanks for their work!