网易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;
}
时间: 2024-08-08 05:28:45

网易2017秋招编程题——回文序列 解题报告的相关文章

网易2017秋招编程题集合-牛客网

网易2017秋招编程题集合-牛客网 链接:https://www.nowcoder.com/questionTerminal/0147cbd790724bc9ae0b779aaf7c5b50来源:牛客网 如果一个数字序列逆置之后跟原序列是一样的就称这样的数字序列为回文序列.例如: {1, 2, 1}, {15, 78, 78, 15} , {112} 是回文序列, {1, 2, 2}, {15, 78, 87, 51} ,{112, 2, 11} 不是回文序列. 现在给出一个数字序列,允许使用一

网易2017秋招编程题集合_以下代码全部来自牛客网

如果一个数字序列逆置之后跟原序列是一样的就称这样的数字序列为回文序列.例如:{1, 2, 1}, {15, 78, 78, 15} , {112} 是回文序列, {1, 2, 2}, {15, 78, 87, 51} ,{112, 2, 11} 不是回文序列.现在给出一个数字序列,允许使用一种转换操作:选择任意两个相邻的数,然后从序列移除这两个数,并用这两个数字的和插入到这两个数之前的位置(只插入一个和).现在对于所给序列要求出最少需要多少次操作可以将其变成回文序列. 链接:https://ww

网易2017春招[编程题]分饼干@Java

o6b19TK菜3孤Whttp://www.docin.com/app/user/userinfo?userid=178838282 eO白懊窒1瘫9肯3钠E山段http://huiyi.docin.com/hwhx2495 53k腾7懦95泛纤3Vhttp://tushu.docin.com/sina_5847498140 柑5v课9N1缴遮9毖Fhttp://www.docin.com/app/user/userinfo?userid=179253259 h3G伟t涝r焉布7R9http:/

算法是什么我记不住,But i do it my way. 解一道滴滴出行秋招编程题。

只因在今日头条刷到一篇文章,我就这样伤害我自己,手贱. 刷头条看到一篇文章写的滴滴出行2017秋招编程题,后来发现原文在这里http://www.cnblogs.com/SHERO-Vae/p/5882357.html.看了下,挺有意思,于是就想了想,又写了写,最终撸出来了.刚开始一看顿时感觉很熟悉,大学数据结构和算法课肯定讲过相关东西,什么深度搜索,广度搜索,最优路径,最优解...但是现在你让我说个一二三,我还就只记住几个名字,说不定名字都记错.我向来不喜欢死记东西,能查到的真的不想背下来,而

滴滴出行秋招编程题

算法是什么我记不住,But i do it my way. 解一道滴滴出行秋招编程题. 只因在今日头条刷到一篇文章,我就这样伤害我自己,手贱. 刷头条看到一篇文章写的滴滴出行2017秋招编程题,后来发现原文在这里http://www.cnblogs.com/SHERO-Vae/p/5882357.html.看了下,挺有意思,于是就想了想,又写了写,最终撸出来了.刚开始一看顿时感觉很熟悉,大学数据结构和算法课肯定讲过相关东西,什么深度搜索,广度搜索,最优路径,最优解...但是现在你让我说个一二三,

网易2017秋招笔试题3:最长公共子括号序列长度

[问题来源]网传的2017网易秋招笔试题 [问题描述] [算法思路] 下面的解题思路摘自  http://www.cnblogs.com/Atanisi/p/7500186.html 刚看到题我就想到暴力解,深搜出所有合法的括号序列,再依次比较公共子序列的长度,返回最长的.但是深搜一般和路径有关,这道题仅仅需要最大公共子序列的长度.而我们发现最大公共子序列的长度就是 s.size() - 1(当且仅当修改距离为 1 时 LCS 最大), 那么我们就想到,可以变换 s 中一个括号的位置,枚举所有的

网易2017秋招---优雅的点

做了这么多的编程题,其实我感觉题目只要找到思路 ,代码实现是非常容易的,因为程序语言不懂的地方可以百度, 而为一个题目找到思路却是没办法搜索的,除非题目是现成可以被搜索的 这个题目求解十分容易,用O(n2)的算法 进行遍历,找到非x,y轴上的的坐标点 就+=4  在x y轴就+=2 思考花了3分钟,编码2分钟,比较入门的题 package com.net163.question; import org.junit.Test; /** * Created by Administrator on 2

采购单(京东2017秋招真题)

本来也不算很难的一道题,但是总是只通过60% 或者 80% 一眼就看出思路,代码也不难的题就是不能全部通过也是神烦,应该是格式上的问题,也不算完全弄明白了,简单说说,作为一种经验. 思路:给价钱 和 每种物品的个数排序 最贵:最高价买最多的物品,累加 最低:最低价买最多的物品.累加 语句:list.count()    list.sort()    set(list)等 以下为正确的python语句 while 1:     r = raw_input()     if r != '':    

1.虎牙直播2019秋招编程题

第一题: #include <iostream> #include <string> using namespace std; bool IsVoChar(char c) { return (c == 'a') || (c == 'e') || (c == 'o') || (c == 'i') || (c == 'u') || (c == 'A') || (c == 'E') || (c == 'O') || (c == 'I') || (c == 'U'); } string r