演算法調整隊形

2021-09-30 14:37:56 字數 3354 閱讀 9905

來自:2017

年網易春招筆試題三

在幼兒園有

n個小朋友排列為乙個隊伍,從左到右乙個挨著乙個編號為(

0~n-1

)。其中有一些是男生,有一些是女生,男生用『

b』表示,女生用『

g』表示。小朋友們都很頑皮,當乙個男生挨著的是女生的時候就會發生矛盾。作為幼兒園的老師,你需要讓男生挨著女生或者女生挨著男生的情況最少。你只能在原隊形上進行調整,每次調整只能讓相鄰的兩個小朋友交換位置,現在需要盡快完成隊伍調整,你需要計算出最少需要調整多少次可以讓上述情況最少。

例如:ggbbg-->ggbgb-->gggbb

這樣就使之前的兩處男女相鄰變為一處相鄰,需要調整隊形2次。

輸入描述:

輸入資料報括乙個長度為

n且只包含g和

b的字串。

n不超過50。

輸出描述:

輸出乙個整數,表示最少需要的調整隊伍的次數。

輸入例子1:

ggbbg

輸出例子1:

2分析:

要使男生挨著女生或者女生挨著男生的情況最少,則調整後的隊形只存在

gg…gb..bb

和bb…bg…ggg

兩種情況,即,問題變成將原字串變為上述兩種情況中移動次數最少的那一種情況。

先寫出函式原型:

int mincount(constchar *p);

輸入為乙個字串,輸出為乙個整數。

每次只能交換相鄰的兩個元素,考慮其中一種情況

gg…gb…bb:

1、從左到右遍歷,當遇到

g時不變,判斷已出現

g的個數,若等於

g的總數則退出迴圈; 2

、當遇到

b時,看下乙個元素是否為

g,是的話交換兩個位置,遍歷下標加一,交換次數加一,判斷已出現

g的個數,若等於

g的總數則退出迴圈; 3

、下乙個元素是

b時,繼續判斷下個元素是否為

b,否則直到下個元素是g,將

g一步一步左移交換位置,判斷已出現

g的個數,若等於

g的總數則退出迴圈; 4

、再重複上述步驟直到退出迴圈。

最後返回兩種情況的次數,將最小值作為最終的結果。

下面給出**(

c++):

#include 

using namespace std;

#define max 50

// 函式返回最終結果

int mincount(const char* p);

// 輸入字串並按照字元先後標準排序,返回次數

int sort(char*p,int len,char,char);

// 交換函式

void swap(char &,char &);

int main()

int mincount(const char* p)

// 判斷是否有非法字元

for(i = 0; i < len; i++) }

strcpy(tmp,p);

//兩種方式的排序所需的次數

m1 = sort(tmp,len,'g','b');

cout << "method1 : " << m1 << endl;

strcpy(tmp,p);

m2 = sort(tmp,len,'b','g');

cout << "method2 : " << m2 << endl;

return min(m1,m2);

}int sort(char*p,int len,char a,char b)

// 1、從左到右遍歷

for(i = 0; i < len; i++)

// 2、當遇到b時

else

// 出現a,次數再+1

tmpnum++;

// 每次交換兩個位置,交換次數加一

while(j > i)

// 4、判斷已出現a的個數,若等於a的總數則退出迴圈

if(tmpnum == numa)

break;

} }return ncount;

}

執行結果,當輸入為

ggbbg時:

當輸入為

gbbgbggbbb時:

進一步討論,題目需要將乙個字串按照類別分成兩堆(可以看成簡化的三色旗問題),

若已知排序後的結果,只需判斷某個字元在向目的方向移動時,中間有幾個其他字元,就可以知道該字元所需移動次數,最後計算每個字元需要的移動次數的總和,結果就為總共所需要的交換次數。

下面給出**(

c++):

#include 

using namespace std;

#define max 50

int func(const char *p)

// 判斷是否有非法字元

for(i = 0; i < len; i++) }

for(i = 0; i < len; i++)

}m1 += tmp;

tmp = 0;

} }tmp = 0;

for(i = 0; i < len; i++)

}m2 += tmp;

tmp = 0;

} }cout << "method1 : " << m1 << endl;

cout << "method2 : " << m2 << endl;

return min(m1,m2);

}int main()

下面是輸出結果:

總結,本題應該不是主要考慮排序演算法,由於題目所給總數不超過

50,也不需要過分強調演算法複雜度,所得的結果只要避免男男交換或**交換即可。為避免需要比較兩種順序的結果大小,提高速度,應該可預先判斷怎樣排序是最優的,如判斷中點兩邊b和

g的數量,若左邊

b的數量大於右邊,則可近似認為

b排在左邊比排在右邊會交換更少的次數,這樣就可以只考慮

b排在左邊的情況,也符合實際情況,當然是否一定正確需要嚴格證明。

網易2017演算法題 調整隊形

題目是這樣的 在幼兒園有n個小朋友排列為乙個隊伍,從左到右乙個挨著乙個編號為 0 n 1 其中有一些是男生,有一些是女生,男生用 b 表示,女生用 g 表示。小朋友們都很頑皮,當乙個男生挨著的是女生的時候就會發生矛盾。作為幼兒園的老師,你需要讓男生挨著女生或者女生挨著男生的情況最少。你只能在原隊形上...

調整隊形 TJOI2007

給定乙個初始的序列以及四種操作,問最少操作多少次可以是序列變為回文序列。操作如下 在隊伍左側或右側新增乙個數 在隊伍中插入乙個數 刪除乙個數 改變乙個數的值 看到給定的序列和改數的操作 其實還是因為詢問是最少操作次數 可以想到區間dp。設子狀態 dp i j 表示將區間 i,j 變為回文序列的最少操...

網易面試題 調整隊形

在幼兒園有n個小朋友排列為乙個隊伍,從左到右乙個挨著乙個編號為 0 n 1 其中有一些是男生,有一些是女生,男生用 b 表示,女生用 g 表示。小朋友們都很頑皮,當乙個男生挨著的是女生的時候就會發生矛盾。作為幼兒園的老師,你需要讓男生挨著女生或者女生挨著男生的情況最少。你只能在原隊形上進行調整,每次...