面试练习题汇总
  • 说明
  • C/C++ 问答题汇总
  • 编程题汇总
    • 腾讯 2017 暑期实习生编程题
      • 构造回文
      • 算法基础-字符移位
      • 有趣的数字
    • 剑指 Offer 编程题练习
      • 二维数组中的查找
      • 从尾到头打印链表
      • 旋转数组的最小数字
      • 替换空格
      • 用两个栈实现队列
      • 重建二叉树
    • 网易 2017 校招笔试编程题
      • 二进制权重
      • 平方串
      • 数位和
  • 安全测试开发相关面试
    • 安全测试类面试参考
    • 业务安全类面试参考
    • 测试开发类面试参考
  • 深信服sangfor相关
    • 深信服acm相关
    • 测试类面试参考
    • 智安全杯
      • 智安全杯-2018比赛
      • 智安全杯-2019初赛
      • 智安全杯-2019复赛
  • 软件测试题汇总
  • 计算机知识题汇总
    • 前 75 题
    • 75 题以后
  • Python 语言特性
    • 1 Python的函数参数传递
    • 2 @staticmethod和@classmethod
    • 3 类变量和实例变量
    • 4 Python中单下划线和双下划线
    • 5 args and *kwargs
    • 6 面向切面编程AOP和装饰器
    • 7 单例模式
    • 8 Python 函数式编程
    • 9 Python 里的拷贝
  • stackoverflow-about-Python
    • Python中关键字yield有什么作用?
    • [Python中的元类(metaclass)是什么?](stackoverflow-about-Python/Python中的元类(metaclass)是什么.md)
    • Python中如何在一个函数中加入多个装饰器?
    • 如何判断一个文件是否存在?
    • 如何调用外部命令?
    • 枚举类型的使用?
    • 在Windows下安装pip?
    • 字典合并问题
    • 在Android上运行Python
    • 根据字典值进行排序
    • 在函数里使用全局变量
    • 变化的默认参数
    • 装饰器classmethod和staticmethod的区别
    • 检查列表为空的最好办法
    • 怎么用引用来改变一个变量
    • 检查文件夹是否存在的操作
    • name=main的作用
    • super与init方法
    • str与repr的区别
    • 循环中获取索引
    • 类里的静态变量
    • 怎么在终端里输出颜色?
    • 为什么用pip比用easy_install的好?
    • join的问题
    • 把列表分割成同样大小的块
    • 为什么代码在一个函数里运行的更快
    • 如何快速合并列表中的列表?
    • 如何知道一个对象有一个特定的属性?
    • 如何通过函数名的字符串来调用这个函数?
    • 单下划线和双下划线的含义?
  • Python 面试编程题
    • 1 台阶问题 斐波那契
    • 2 变态台阶问题
    • 3 矩形覆盖
    • 4 杨氏矩阵查找
    • 5 去除列表中的重复元素
    • 6 链表成对调换
    • 7 创建字典的方法
    • 8 合并两个有序列表
    • 9 二分查找
    • 10 快排
    • 11 找零问题
    • 12 二叉树相关
    • 13 单链表逆置
Powered by GitBook
On this page
  • 题目描述
  • 参考资料
  • 分析
  • Python 解答
  • C 语言版本 1
  • C 语言版本 2

Was this helpful?

  1. 编程题汇总
  2. 腾讯 2017 暑期实习生编程题

构造回文

Previous腾讯 2017 暑期实习生编程题Next算法基础-字符移位

Last updated 5 years ago

Was this helpful?

题目描述

给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?输出需要删除的字符个数。

输入描述:输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.

输出描述:对于每组数据,输出一个整数,代表最少需要删除的字符个数。

输入例子:

abcdagoogle

输出例子:

22

参考资料

分析

对于这题来说,插入字符和删除字符使其成为回文串,答案是一样的.首先求s的反串rs,然后对s和rs求最长公共子序列,要删除的字符个数就是 LCS.

Python 解答

自己用 Python 写了, 虽然结果正确, 但是超时了。思路是用动态规划。

#!/bin/env python3
# -*- coding: utf-8 -*-
# version: Python3.X
"""
# 题目描述
给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?输出需要删除的字符个数。

# 参考资料
    http://www.voidcn.com/blog/Do_Know/article/p-5978576.html

# 分析
对于这题来说,插入字符和删除字符使其成为回文串,答案是一样的.

首先求s的反串rs,然后对s和rs求最长公共子序列,要删除的字符个数就是 LCS.
"""

__author__ = '__L1n__w@tch'

MAX_LENGTH = 1010  # 1 <= s <= 1000


# 答案用动态规划解决的
def dynamic_solve(s):
    """
    动态规划求取构造回文要删除的字符个数
        dp[i][j] 表示 s1 的前 i 个字符串, s2 的后 j 个字符串中的最大公共字串

    动态方程:
        dp[i + 1][j + 1] = dp[i][j] + 1 if s1[i] == s2[j] else max(dp[i][j + 1], dp[i + 1][j])
    :param s: 原始字符串
    :return: 需要删除的字符个数
    """
    # 先求反串
    length = len(s)
    reversed_s = s[::-1]

    # 求最长公共子序列
    dp = [[0 for i in range(MAX_LENGTH)] for i in range(MAX_LENGTH)]  # 初始化

    for i in range(length):
        for j in range(length):
            if s[i] == reversed_s[j]:
                dp[i + 1][j + 1] = dp[i][j] + 1
            else:
                dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j])

    return length - dp[length][length]  # 长度减去最长公共子序列即为所求


if __name__ == "__main__":
    tests = ["", "a", "ab", "abcda", "google",
             "zgtklhfzomzjckwmluvivvcmhjrwkuvcjrxojobpdedpamdshcwwsetfbacvonecrdvugeibglvhxuymjvoryqjwullvzglqazxrdmczyvbgakjagttrezmvrlptiwoqkrtxuroeqmryzsgokopxxdpbejmtwvpnaqrgqladdszhdwxfckmewhdvihgvacueqhvwvjxoitlpfrckxkuksaqzjpwgoldyhugsacflcdqhifldoaphgdbhaciixouavqxwlghadmfortqacbffqzocinvuqpjthgekunjsstukeiffjipzzabkuiueqnjgkuiojwbjzfynafnlcaryygqjfixaoeowhkxkbsnpsvnbxuywfxbnuoemxynbtgkqtjvzqikbafjnpbeirxxrohhnjqrbqqzercqcrcswojyylunuevtdhamlkzqnjrzibwckbkiygysuaxpjrgjmurrohkhvjpmwmmtpcszpihcntyivrjplhyrqftghglkvqeidyhtmrlcljngeyaefxnywpfsualufjwnffyqnpitgkkyrbwccqggycrvoocbwsdbftkigrkcbojuwwctknzzmvhbhbfzrqwzllulbabztqnznkqdyoqnrxhwavqhzyzvmmmphzxbikpharseywpfsqyybkynwbdrgfsaxduxojcdqcjuaywzbvdjgjqtoffasiuhvxcaockebkuxpiomqmtvsqhnyxfjceqevqvnapbk"]
    for each_test in tests:
        print(dynamic_solve(each_test))

C 语言版本 1

自己用 C 又重写了一遍,期望能通过,结果发现提示说答案错,同样的数据,在网上测试的时候结果错了,在本机测试的时候自己出来的答案是对的。说明不是代码问题,而是题目所给字符串的输入问题,尝试用文件读入数据解决结果发现还是没错,所以就不知道了。以下是代码:

//
// Created by w@tch on 16/7/21.
//

#include <stdio.h>
#include <string.h>

#define MAX_LENGTH 1001

char *strrev(char *s) {
    if (s == NULL || s[0] == '\0')
        return s;

    for (char t, *p = s, *q = s + strlen(s) - 1; p < q; p++, q--) {
        t = *p;
        *p = *q;
        *q = t;
    }

    return s;
}

int dynamic_solve(char *s) {
    // 先求反串
    char *reverse_s = new char(strlen(s) * sizeof(char));
    strcpy(reverse_s, s);
    strrev(reverse_s);

    // 初始化
    int length = strlen(s);
    int i, j;
    int dp[MAX_LENGTH][MAX_LENGTH] = {0};

    // 求最长公共子序列
    for (i = 0; i < length; ++i) {
        for (j = 0; j < length; ++j) {
            if (s[i] == reverse_s[j]) {
                dp[i + 1][j + 1] = dp[i][j] + 1;
            }
            else {
                dp[i + 1][j + 1] = dp[i][j + 1] > dp[i + 1][j] ? dp[i][j + 1] : dp[i + 1][j];
            }
        }
    }

    return length - dp[length][length]; // 长度减去最长公共子序列即为所求
}

int main(void) {
//    FILE *f = fopen("/Users/L1n/Desktop/C_C++ Projects/C_C_Plus_Plus_Knowledge/data.txt", "r");
    FILE *f = fopen("data.txt", "r");
    if (f != NULL) {
        char s[MAX_LENGTH] = {0};
        while (fscanf(f, "%s", s) != EOF) {
            printf("%d\n", dynamic_solve(s));
        }
    }


    return 0;
}

/* 提交用
int main() {
 char s[MAX_LENGTH] = {0};
 while (scanf("%s", s) != EOF) {
 printf("%d\n", dynamic_solve(s));
 }
}
*/

C 语言版本 2

为了通过,照着网上的答案又重新敲了一遍。这回提交正确了,最终代码如下:

// 构造回文, 解决方案 2, 思路一样都是动态规划, 不过用的库函数不一样
// Created by w@tch on 16/7/23.
#include <string>
#include <iostream>
#include <algorithm> // reverse, max 函数均位于该头文件中
#include <vector>

using namespace std;

int main(void) {
    string s;
    string rs;
    while (cin >> s) {
        rs = s; // 复制
        reverse(rs.begin(), rs.end()); // 逆置

        // 动态规划初始化
        int length = s.size();
        vector<vector<int>> lcs(length + 1, vector<int>(length + 1, 0));

        /* 思路解释
         * 两个字符串 BDCABA 和 ABCBDAB, 字符串 BCBA 和 BDAB 都是是它们的最长公共子序列
         * lcs[i][j] 表示 s1 长度为 i, s2 长度为 j 时的最大公共子串长度
         * 现在已知 lcs[i - 1][j] 即 s1 长度为 i - 1, s2 长度为 j 时的最大公共子串长度
         * 而且已知 lcs[i][j - 1] 即 s1 长度为 i, s2 长度为 j - 1 时的最大公共子串长度
         * 当 s1 与 s2 同时增加一个字符之后, 判断 lcs[i][j] 的最大公共子串长度
         * 动态方程, 如果 s1 和 s2 增加的字符是相同的, 则最大公共子串长度可以 + 1, 否则最大公共子串长度为 lcs[i-1][j] 或 lcs[i][j-1]
        */
        for (int i = 1; i <= length; i++) {
            for (int j = 1; j <= length; j++) {
                if (s[i - 1] == rs[j - 1]) {
                    lcs[i][j] = lcs[i - 1][j - 1] + 1;
                }
                else {
                    lcs[i][j] = max(lcs[i][j - 1], lcs[i - 1][j]);
                }
            }
        }

        cout << length - lcs[length][length] << endl;
    }
}
删除最少字符使字符串成为回文串