1. 程式人生 > >演算法設計與分析 第三週

演算法設計與分析 第三週

題目描述

在這裡插入圖片描述

選題原因

之前兩週做了兩道中等難度的題目,結果還算不錯,因此這次準備選一道困難的題目。篩選了圖演算法,開始選了一道冗餘連線II,完成之後發現題目有一些bug。當選擇的時候,題目要求有多條邊冗餘的時候需要選擇先出現的邊,但是實際測試的時候並不是以這樣的標準。因此放棄了冗餘連線II,重新選擇了這一題情侶牽手

題目分析

突然一看,這一題彷彿和圖演算法沒有什麼關係。但是實際上這道題的核心就是有環圖
我們先來看看這一題怎麼解。在觀察這道題的時候不難會產生疑問:當我們交換的座位順序不同的時候會不會對結果有影響?這樣得到的結果還是最少次數嗎?
但是結合有環圖的思想來看,最優的解法就是不停的讓一個人離開,去找她的伴侶。
想要理解,我們需要用有環圖

的思想來類比。
我們把每兩個相鄰的座位看作一個節點(0,1或2,3這樣的),而如果兩個座位換了的話,就看做兩個節點有聯絡,我們就用一條來把他們連線起來。
下面,我們需要理解兩個思想:

  • 一個人出去找座位開始,直到找到的剛好是自己的情侶為終止,可以構成一條單鏈。
  • 相鄰兩條單鏈如果連線,會使步驟增加。

從一條單鏈任意節點開始,最後需要的步數相同。

我們還是按照原有的思想,先找出一條單鏈。

在這裡插入圖片描述

若是我們改為從B節點出發,那麼結果會是這樣

在這裡插入圖片描述

很容易發現,只要是從這一條路上開始,無論哪一個節點,最後都會使用相同的步驟到達終點。(可以試著構造一條虛環,便於理解)

相鄰兩條單鏈連線會使得消耗更多的步驟

這一條理解起來就有些困難了,那就讓我們引入一些概念:假設A節點一對情侶為a1, a2; 同理,B節點情侶為b1, b2。
讓我們構造兩條不相關的單鏈。

在這裡插入圖片描述

如果我們將他們首尾相連,交換他們的元素,那麼會發生什麼情況?

在這裡插入圖片描述

我們驚奇的發現,他們連成了一條線?為什麼會這樣呢?其實很容易理解:我們將節點裡的每一個元素看成一個連線因子,當兩條鏈的連線因子交換了之後,兩條鏈就必然產生聯絡;而每一條原本都是獨立的,當一個因子交換出去了之後,也只會有一個元素需要和外界連線,如此一來,就會構成一條鏈。
但這樣,步數增加了多少?2步。

如果我們交換中間節點呢?

在這裡插入圖片描述

我們發現,又構成了一條鏈?其實,也不是所有情況都會構成一條鏈,有時也會是交錯的連線。但是無論怎樣,步驟都會增加。

解題思路

  • 準備一個數組將儲存進每一個人對應的座位號
  • 從開頭開始遍歷,每兩位檢驗一次,如果是情侶則跳過,否則就需要進入換座位的迴圈
  • 找到情侶所在的位置,將鄰座和情侶互換
  • 換走的鄰居到達了新地方,查詢自己情侶的位置,讓鄰座和自己的情侶換座位
    若換到新座位,旁邊恰好是自己的情侶,則終止。

核心程式碼部分

計算座位號

        //儲存每個人座位號
        for (int i = 0; i < max; i++) {
            pos[row[i]] = i;
        }

換座位

int lover_site = pos[lover];
                //當前旁邊旅客序號及座位號
                int beside = row[i + 1];
                int beside_site = pos[beside];
                //每次配對,讓當前座位的情侶過來,與旁邊的人交換,旁邊的人交換過去後,再次迴圈
                //如果交換過去的人旁邊就是自己的情侶,則迴圈結束
                while (my_site / 2 != lover_site / 2) {
                    sum++;
                    row[beside_site] = lover;       //情侶過來
                    pos[beside] = lover_site;
                    
                    row[lover_site] = beside;       //原座位走開
                    pos[lover] = beside_site; 
                    
                    //計算走了的旅客現在的情侶,旁邊旅客序號、座位號,並再次迴圈
                    me = beside;
                    my_site = pos[me];
                    if (me % 2 == 0) {
                        lover = me + 1;
                    } else {
                        lover = me - 1;
                    }
                    lover_site = pos[lover];
                    if (my_site % 2 == 0) {
                        beside = row[my_site + 1];
                    } else {
                        beside = row[my_site - 1];
                    }
                    beside_site = pos[beside];
                }

原始碼

class Solution {
public:
    int minSwapsCouples(vector<int>& row) {
        int max = row.size();
        int pos[max] = {0};
        //儲存每個人座位號
        for (int i = 0; i < max; i++) {
            pos[row[i]] = i;
        }
        
        int sum = 0;
        
        int i = 0;
        while (i < max) {
            //座位上是一對情侶
            if (row[i] / 2 == row[i + 1] / 2) {
                i = i + 2;
            } else {
                //當前序號及座位號
                int me = row[i];
                int my_site = pos[i];
                //情侶序號及座位號
                int lover;
                if (me % 2 == 0) {
                    lover = me + 1;
                } else {
                    lover = me - 1;
                }
                int lover_site = pos[lover];
                //當前旁邊旅客序號及座位號
                int beside = row[i + 1];
                int beside_site = pos[beside];
                //每次配對,讓當前座位的情侶過來,與旁邊的人交換,旁邊的人交換過去後,再次迴圈
                //如果交換過去的人旁邊就是自己的情侶,則迴圈結束
                while (my_site / 2 != lover_site / 2) {
                    sum++;
                    row[beside_site] = lover;       //情侶過來
                    pos[beside] = lover_site;
                    
                    row[lover_site] = beside;       //原座位走開
                    pos[lover] = beside_site; 
                    
                    //計算走了的旅客現在的情侶,旁邊旅客序號、座位號,並再次迴圈
                    me = beside;
                    my_site = pos[me];
                    if (me % 2 == 0) {
                        lover = me + 1;
                    } else {
                        lover = me - 1;
                    }
                    lover_site = pos[lover];
                    if (my_site % 2 == 0) {
                        beside = row[my_site + 1];
                    } else {
                        beside = row[my_site - 1];
                    }
                    beside_site = pos[beside];
                }
                i = i + 2;
            }
        }
        return sum;
    }
};

執行結果

在這裡插入圖片描述

相關推薦

演算法設計分析

題目描述 選題原因 之前兩週做了兩道中等難度的題目,結果還算不錯,因此這次準備選一道困難的題目。篩選了圖演算法,開始選了一道冗餘連線II,完成之後發現題目有一些bug。當選擇的時候,題目要求有多條邊冗餘的時候需要選擇先出現的邊,但是實際測試的時候並不是

演算法設計分析次作業

#leetcode 685.Redundant Connection II In this problem, a rooted tree is a directed graph such that, there is exactly one node (the

演算法設計分析leetcode

Longest Valid Parentheses Given a string containing just the characters ‘(’ and ‘)’, find the length of the longest valid (well-

演算法設計分析Leetcode作業

Edit Distance Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2. You hav

短除法求最大公約數(轉自演算法設計分析版)

#include<stdio.h> int main() {     /*短除法求最大公約數*/     int i;     int j;     int a;     int b;     int t;     int c=1;     scanf("%d%

演算法設計分析 IPO

1.題目描述 2.選題原因 學習了貪心演算法,隨機選擇了一道題目。 3.題目分析及演算法 3.1分析 貪心演算法的本質即是:每一步都選擇當前最好的點,不一定能夠得到全域性最優解,但一定要得到區域性最優解。結合這道題來考慮,按照貪心演算法的思路,在

演算法設計分析》第二作業

《演算法設計與分析》第二週作業 標籤(空格分隔): 課堂作業 《演算法設計與分析》第二週作業 題目概要 思路 嘗試一 嘗試二

演算法設計分析》第一作業

《演算法設計與分析》第一週作業 標籤(空格分隔): 課堂作業 姓名:李** 學號:16340114 題目:Valid Parentheses(https://leetcode.com/problems/valid-parentheses/description/) 題目

演算法設計分析

53.Course Schedule There are a total of n courses you have to take, labeled from 0 to n-1. Some courses may have prerequisites, for

演算法設計分析四周練習(圖論)

Network Delay Time 1. 題目 There are N network nodes, labelled 1 to N. Given times, a list of travel times as directed edges times[i

演算法設計分析1章 演算法概述

第1章 演算法概述(窮舉演算法) 重要人物:Alan Turing(圖靈機)、Donald Knuth(TEX系統) 演算法:解決問題的一種方法或一個過程 特性:有窮性(Finiteness)、確定性(Definiteness)、可行性(effectivenes

《計算機演算法設計分析 4版 (王曉東) 課後答案[1-9章]》pdf版電子書附下載連結+30個總結JVM虛擬機器的技術文排版好(收藏版)

技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結都會有特別好的作用。 對於每一章的知識,先閱讀標題,弄懂大概講的是什麼主題,再去快速看一遍,不懂也沒有關係,但是一定要在不懂的

《計算機演算法設計分析 2版+3版+4版 (王曉東) 》原書附答案pdf版電子書附下載連結+30個總結JVM虛擬機器的技術文排版好(收藏版)

技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結都會有特別好的作用。 對於每一章的知識,先閱讀標題,弄懂大概講的是什麼主題,再去快速看一遍,不懂也沒有關係,但是一定要在不懂的

演算法設計分析作業

《演算法設計與分析》第三週作業 標籤(空格分隔): 課堂作業 文章目錄 《演算法設計與分析》第三週作業 @[toc] 題目概要 思路 思路一 思路二 具體實

演算法設計分析作業題】十一:20. Valid Parentheses

題目 C++ solution class Solution { public: bool isValid(string s) { stack<char> cstack; for (int i = 0; i < s.si

演算法設計分析十一作業

《演算法設計與分析》第十一週作業 標籤(空格分隔): 課堂作業 文章目錄 《演算法設計與分析》第十一週作業 @[toc] 題目概要 思路 具體實現 心得 原始碼:

演算法設計分析十二作業

《演算法設計與分析》第十二週作業 標籤(空格分隔): 課堂作業 文章目錄 《演算法設計與分析》第十二週作業 @[toc] 題目概要 思路 具體實現 心得 原始碼:

演算法設計分析作業

《演算法設計與分析》第十週作業 標籤(空格分隔): 課堂作業 文章目錄 《演算法設計與分析》第十週作業 @[toc] 題目概要 思路 具體實現 心得 原始碼:

演算法設計分析作業

《演算法設計與分析》第八週作業 標籤(空格分隔): 課堂作業 文章目錄 《演算法設計與分析》第八週作業 @[toc] 題目概要 思路 具體實現 心得 原始碼:

演算法設計分析作業

《演算法設計與分析》第七週作業 標籤(空格分隔): 課堂作業 文章目錄 《演算法設計與分析》第七週作業 @[toc] 題目概要 思路 具體實現 心得 原始碼: