Leetcode 1122. 數組的相對排序【二分搜索&桶排序】

問題描述

給你兩個數組,arr1arr2

  • arr2 中的元素各不相同
  • arr2 中的每個元素都出現在 arr1
    arr1 中的元素進行排序,使 arr1 中項的相對順序和 arr2 中的相對順序相同。未在 arr2 中出現過的元素需要按照升序放在 arr1 的末尾。

示例:

輸入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
輸出:[2,2,2,1,4,3,3,9,6,7,19]

解題報告

二分搜索

首先將數組 arr1 進行排序
然後依次遍歷數組 arr2 中的元素,在數組 arr1 中找到其所有位置,然後將其換到arr1 的前面。最後返回數組 arr1 即可。
時間複雜度: O(max(arr1logarr1,arr2logarr1))O(max(|arr1|\cdot log |arr1|, |arr2|\cdot log |arr1|))
空間複雜度:O(1)O(1)

具體實現上:

  • 二分查找一個有序數組中元素出現的第一個位置
int find(vector<int>& nums, int target)
{
    int l=0,r=nums.size()-1,mid;
    while(l<=r)
    {
        mid=(l+r)/2;
        if (target>nums[mid]) l=mid+1;
        else r=mid;
        if (r==l) break;
    }
    return l;
}

接下來搜索該元素共有多少個,首先將這些元素刪除,然後將其插入到 arr1 的前面。這樣處理之後,接下來的元素還是有序的,依然可以二分搜索。

桶排序

注意到這題數組中每個數的取值範圍較小——和數組大小相同,所以用桶排序法非常方便。
首先創建一個大小爲 1001 的桶,遍歷數組 arr1,每個桶中記錄該桶出現的次數。
然後遍歷數組 arr2,按照 arr2 數組中的元素順序,將各個桶放到結果數組中,最後將剩餘的桶依次放到結果數組中即可。
時間複雜度:O(max(arr1,arr2))O(max(|arr1|,|arr2|))
空間複雜度:O(max(arr1,max(arr1)))O(max(|arr1|,max(arr1)))

實現代碼

二分搜索實現

class Solution {
public:
       vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2) {
        int tmp = 0,l=0,r=arr1.size(),mid,counter;
        sort(arr1.begin(), arr1.end());
        for(int i = 0;i<arr2.size();++i){
            l=tmp,r=arr1.size()-1,counter=1;
            while(l<=r){
			    mid=(l+r)/2;
			    if (arr2[i]>arr1[mid]) l=mid+1;
                else r=mid;
			    if (r==l) break;
		    }
            int temp=arr1[l],index=l;
            while(true){
                if(l<arr1.size()-1&&temp==arr1[l+1]){
                    counter++;
                    l++;
                }
                else break;
            }
            arr1.erase(arr1.begin()+index,arr1.begin()+index+counter);
            arr1.insert(arr1.begin()+tmp, counter, temp);
            tmp+=counter;
        }
        return arr1;
    }
};

桶排序實現

class Solution{
    public:
        vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2){
            vector<int>bucket(1001,0),ans;
            int counter=0;
            for(int i=0;i<arr1.size();i++)
                bucket[arr1[i]]=bucket[arr1[i]]+1;

            for(int i=0;i<arr2.size();i++){
                ans.insert(ans.end(), bucket[arr2[i]], arr2[i]);
                bucket[arr2[i]]=0;
            }

            for(int i=0;i<bucket.size();i++){
                if(bucket[i]>0) ans.insert(ans.end(), bucket[i], i);
            }
            return ans;
        }
};

補充

二分查找一個有序數組中元素出現的第一個位置

int find(vector<int>& nums, int target)
{
    int l=0,r=nums.size()-1,mid;
    while(l<=r)
    {
        mid=(l+r+1)/2;
        if (target>=nums[mid]) l=mid;
        else r=mid-1;
        if (r==l) break;
    }
    return r;
}

參考資料

[1] Leetcode 1122. 數組的相對排序
[2] 有序數組的二分查找—查找元素第一次和最後一次出現的位置

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章