數組排序 使得交換次數最少


題目:   

給定一個包含1-n的數列,我們通過交換任意兩個元素給數列重新排序。

求最少需要多少次交換,能把數組排成按1-n遞增的順序,(數組中的元素互不重復)。

 

比如 初始狀態 5 4 3 2 1 。交換5和1的位置 得到 1 4 3 2 5,再交換4 2的位置得到 1 2 3 4 5.只需要兩次即可。

方法一:

 第一個數排序之后應該是1,但此時第一個位置是5,那么把5放到5應該在的位置上,

然后再把5原來位置上那個數字放到第一個位置上, 即得到 1 4 3 2 5 。此時第一個位置的數字已經找到 ,往后遍歷位置2.

得到4,接下來把4放到4應該在的位置,得到 1 2 3 4 5.此時已經完全有序。

總結一下就是:

 交換的時候,遍歷數組,判斷當前元素是否在最終位置,否則把它交換到它的最終位置,(即每次交換至少讓其中一個元素被放到其最終位置),這樣統計總交換次數。

int getMinSwaps(vector<int> &nums)
{
    map<int, int>mp;    
    vector<int> sortedNums(nums);
    sort(sortedNums.begin(), sortedNums.end());
    for (int i = 0; i < sortedNums.size(); i++)mp[sortedNums[i]] = i ;//記錄下標索引

    int cnt = 0;
    for (int i = 0; i < nums.size();i++)
    {
        if (nums[i] == sortedNums[i])continue;
        swap(nums[i], nums[mp[nums[i]]]);//交換到nums[i]這個值應該在的位置
        cnt++;
    }
    return cnt;
}

 

方法二:

在原數組中,每個元素添加一個出邊指向它最終的位置,這樣畫完出邊后,

最少會成一個環,最多n個環。 然后原理就是, 最少交換次數=結點數n-形成的環數

int getMinSwaps(vector<int> &nums)
{
//排序 vector<int> nums1(nums); sort(nums1.begin(),nums1.end()); unordered_map<int,int> m; int len = nums.size(); for (int i = 0; i < len; i++){ m[nums1[i]] = i;//建立每個元素與其應放位置的映射關系 } int loops = 0;//循環節個數 vector<bool> flag(len,false); //找出循環節的個數 for (int i = 0; i < len; i++){ if (!flag[i]){//已經訪問過的位置不再訪問 int j = i; while (!flag[j]){ flag[j] = true; j = m[nums[j]];//原序列中j位置的元素在有序序列中的位置 } loops++; } } return len - loops; }

 

參考:

http://blog.csdn.net/lavorange/article/details/16971781

http://blog.csdn.net/codetz/article/details/51152407


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM