算法-數組元素位置調整
這類題目有點特別,不要求我們對數組元素進行像正常排序那樣從大到小或者從小到大,而是要求我們使用O(N)的方法將符合條件的元素排在前面或者後面。其實這是排序的一種變形,不需要我們消滅逆序數。
解決思路有兩類:
1、利用快排思想,將符合條件數據放在前面或後面,一遍遍歷即可完成
2、指針的思想
2、利用冒泡排序思想,我們將符合條件的數據冒在前面,而且我們不需要消滅逆序數,因此每個元素訪問2次,所以時間複雜度仍然是O(N)
1、給定一個數組,將奇數(正數…etc)排在左邊,偶數排在右邊
以奇數爲例,使用快排思想,快排中我們選擇的樞紐元其實是作爲一個條件出現的,而在這裏,只不過這個“樞紐元”換成了奇數偶數而已。
/**
* 利用快排思想,複雜度O(n)
* @param nums
*/
public static void reOrder(int[] nums){
int left=0,right=nums.length-1;
while(left<right){
while (left<right&&(nums[left]&1)==1){left++;}//找到第一個偶數
while(left<right&&(nums[right]&1)==0){right--;}//找到第一個奇數
if(left<right){
swap(nums,left,right);//交換數據
}
}
}
我們還可以有另一種操作: 指針法
使用一個指針指向當前第一個不符合條件的位置,然後遍歷數組,每次遇到符合條件的,我們就可以將其交換,這樣就可以實現題目要求。而且這個方法寫起來非常簡潔
public static void reOrder(int[] nums){
int ptr=0;
for(int i=0;i<nums.length;i++){
if((nums[i]&1)==1){//判斷奇數偶數
swap(nums,ptr++,i);
}
}
}
2、給定一個數組,將奇數(正數…etc)排在左邊,偶數排在右邊(保證相對位置不變)
這類題目和上面相比,稍微複雜了點,這裏要求我們維持相對順序不變。冒泡法給我們帶來了希望。已經冒過的位置不在冒泡,說明每個元素被訪問了兩次,所以時間複雜度爲O(N)
我們也用一個指針指向第一個不符合條件的位置,然後遍歷數組,冒泡冒到那個位置
public static void reOrder(int[] nums){
int ptr=0;
for(int i=0;i<nums.length;i++){
if((nums[i]&1)==1){//判斷奇偶數
int curr=i;
while(curr>ptr){//冒到第一個不符合條件的那個位置
swap(nums,curr,--curr);//前後交換
}
ptr++;
}
}
}
2中的代碼可以直接放在1中使用
//交換元素
public static void swap(int[] nums,int i,int j){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
3、將數組中0移動到數組尾部
題目很簡單,直接套殼就好了。。。
public void moveZeroes(int[] nums) {
int ptr=nums.length-1;
for(int i=nums.length-1;i>=0;i--){
if(nums[i]==0){
int curr=i;
while(curr<ptr){
int temp=nums[curr];
nums[curr]=nums[curr+1];
nums[curr+1]=temp;
curr++;
}
ptr--;
}
}
}
不過,我們其實可以針對本題進行優化。因爲我們知道特定的數據爲0,那麼我們就可以統計非零個數,然後將後面置零。
public void moveZeroes(int[] nums) {
int noZeroIndex=0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=0){
nums[noZeroIndex++]=nums[i];
}
}
for(int i=noZeroIndex;i<nums.length;i++){
nums[i]=0;
}
}