網易2017秋招編程題——回文序列 解題報告
Problem:https://www.nowcoder.com/question/next?pid=2811407&qid=46573&tid=6015849
如果一個數字序列逆置之後跟原序列是一樣的就稱這樣的數字序列為回文序列。例如:
{1, 2, 1}, {15, 78, 78, 15} , {112} 是回文序列,
{1, 2, 2}, {15, 78, 87, 51} ,{112, 2, 11} 不是回文序列。
現在給出一個數字序列,允許使用一種轉換操作:
選擇任意兩個相鄰的數,然後從序列移除這兩個數,並用這兩個數字的和插入到這兩個數之前的位置(只插入一個和)。
現在對於所給序列要求出最少需要多少次操作可以將其變成回文序列。
輸入描述:
輸入為兩行,第一行為序列長度n ( 1 ≤ n ≤ 50) 第二行為序列中的n個整數item[i] (1 ≤ iteam[i] ≤ 1000),以空格分隔。
輸出描述:
輸出一個數,表示最少需要的轉換次數
輸入例子:
4 1 1 1 3
輸出例子:
2
Solution1:
a[i]~a[i+j]變成回文序列,有三種方法:
1.a[i]~a[i+j]合並成一個數
2.a[i]~a[k],a[k+1]~a[i+j]分別合並成一個數,且兩者數值相等
3.a[i]~a[k]合並成一個數,a[l]~a[i+j]合並成一個數,a[k+1]~a[l-1]已構成回文序列,該回文序列長度為f[k+1][l-1]
1 #include <iostream> 2 #define maxn 50 3 #define maxs 1000 4 using namespace std; 5 6 int main() 7 { 8 long n,i,j,k,l,a[maxn+1],f[maxn+1][maxn+1],ans[maxn+1][maxn+1]; 9 cin>>n; 10 for (i=1;i<=n;i++) 11 { 12 cin>>a[i]; 13 ans[i][i]=a[i];14 } 15 //the total of a[i]~a[j] 16 for (i=1;i<n;i++) 17 for (j=i+1;j<=n;j++) 18 ans[i][j]=ans[i][j-1]+a[j]; 19 //length:j+1 20 for (j=0;j<=n-1;j++) 21 //begining position:i 22 for (i=1;i<=n-j;i++) 23 { 24 //a[i]~a[i+j]合並成一個數 25 f[i][i+j]=j; 26 //a[i]~a[k]合並成一個數,a[l]~a[i+j]合並成一個數,a[k+1]~a[l-1]已構成回文序列,該回文序列長度為f[k+1][l-1] 27 for (k=i;k<=i+j-2;k++) 28 for (l=k+2;l<=i+j;l++) 29 if (ans[i][k]==ans[l][i+j]) 30 //(k-i)+((i+j)-l)=k+j-l 31 f[i][i+j]=min(f[i][i+j],f[k+1][l-1]+k+j-l); 32 //a[i]~a[k],a[k+1]~a[i+j]分別合並成一個數,且兩者數值相等 33 for (k=i;k<=i+j;k++) 34 if (ans[i][k]==ans[k+1][i+j]) 35 f[i][i+j]=min(f[i][i+j],j-1); 36 } 37 cout<<f[1][n]<<endl; 38 return 0; 39 }
Solution2:
貪心
長度為n的數列(a[1],a[2],……,a[n]) [1 ≤ a[i] ≤ 1000] 經過變換構成回文序列(b[1],b[2],……,b[m]):
設包含a數列元素個數最少的b[1]為:b[1]=a[1]+a[2]+……+a[p],對應的b[m]=a[q]+a[q+1]+……+a[n]
因為a[i]>0,所以q不同,則b[m]不同,所以b[m]具有唯一性。
當存在p‘,使得p‘>p,且b[1]‘=a[1]+a[2]+……+a[p‘],b[m]‘=a[q‘]+a[q‘+1]+……+a[n], b[1]‘=b[m]‘,
有b[m]‘=b[1]‘>b[1]=b[m],即q‘<q,且a[p+1]+……+a[p‘]=a[q‘]+……+a[q-1]。
當某回文序列b[1]‘=a[1]+a[2]+……+a[p‘],b[m]‘=a[q‘]+a[q‘+1]+……+a[n],
可以修改b[1]‘為:b[1]=a[1]+a[2]+……+a[p],修改b[m]‘為:b[m]=a[q]+a[q+1]+……+a[n]
修改b[2]‘為:b[2]=b[2]‘+a[p+1]+……+a[p‘],修改b[m-1]為:b[m-1]‘=b[m-1]+a[q‘]+……+a[q-1]。
修改後仍為回文序列,且操作次數與修改前相同。
同理可以把b[2]‘修改為b[2](包含a數列元素個數最少),把b[3]‘修改為b[3](包含a數列元素個數最少),依次類推,直到修改後剩下的數能構成回文序列,且被修改的部分(左/右)構成回文序列的部分(左/右),所以能構成回文序列,節省的操作次數為原來剩下的數還要繼續操作變成回文序列的次數。
采用以下方法構成回文序列:
選取包含a數列元素個數最少的b[1]和對應的b[m],在此基礎上選取包含a數列元素個數最少的b[2]和對應的b[m-1],依次類推,直到a所有的元素被選取完畢。
上述已證明任意方法能轉變成此方法,此方法必不會增加操作次數(操作次數與修改前相同),且有可能節省操作次數,所以能證明得到用此方法構成回文序列操作次數最小。
#include <iostream> #define maxn 50 using namespace std; int main() { long n,a[maxn+1],i,l,r,ans=0; cin>>n; for (i=1;i<=n;i++) cin>>a[i]; l=1; r=n; while (l<r) { if (a[l]==a[r]) { l++; r--; } else if (a[l]<a[r]) { l++; a[l]+=a[l-1]; ans++; } else { r--; a[r]+=a[r+1]; ans++; } } cout<<ans<<endl; return 0; }
網易2017秋招編程題——回文序列 解題報告