微软笔试题 回忆(回文方面)


这道题当年我没有做出来,今天微软笔试又碰到了类似的题目

狠心要将这一块吃透

主要还是对动态规划掌握的不够熟练。

 

去年的题目: 最少射击几次

N个瓶子都有编号,每次能射击1个或多个瓶子,如果是回文的就能一次性击倒。最少几次能全击倒?

 

测试

输入:[1, 2]

输出:2

 

输入:[1,3,4,1,5]

输出:3

说明:第一次先射3,变成[1,3,1,5],因为有[1,3,1]回文可以一次击倒,剩下[5]再一次

 

解题思路:

使用动态规划,我们可以将射击分为一系列子任务,用动态规划熟悉的表格表示,score[ i ] [ j ]表示要击倒 i 到 j 瓶子至少需要几次

那么首先就可以知道score[0 ][0] 、score[1][1]、score[2][2] 、、、都为1(原因很显然,只有一个杯子,当然需要一次)

接下来,就继续扩大范围,看两个两个杯子

接下来是三个 三个

一次递增

 

我们可以看到 如果  第 j 个杯子 与 第 j + i个杯子相等

那么 score[j][j+i] 就可以等于 scores[j + 1][j + i - 1] ,也就是夹在他们中间的一段(因为动态规划,规模小的已经最优)

但是这里我们还需要考虑scores[j][j + k] + scores[j + k + 1][j + i] 这样的情况(也就是把整段切分为前后两段)

 

综合以上思路,某位大佬的代码如下:

参考代码:

//
//  main.cpp
//  leetcodeTest
//
//  Created by Qiucheng LIN on 2020/3/25.
//  Copyright © 2020 Qiucheng LIN. All rights reserved.
//



#include <vector>
#include <climits>
#include <iostream>
using namespace std;
 
int main() {
    int N = 8;
    vector<int> bottles = { 1,2,3,2,9,8,9,1 };
    
    vector<vector<int>> scores(N, vector<int>(N));
    for (int i = 0; i < N; i++)
    {
        scores[i][i] = 1;
    }
    for (int i = 1; i < N; i++) {
        for (int j = 0; j < N - i; j++) {
            int min_score = INT_MAX;
            if (bottles[j] == bottles[j + i]) {
                min_score = i > 1 ? scores[j + 1][j + i - 1] : 1;
            }
            for (int k = 0; k < i; k++) {
                int temp = scores[j][j + k] + scores[j + k + 1][j + i];
                if (temp < min_score) {
                    min_score = temp;
                }
            }
            scores[j][j + i] = min_score;
            
        }
        
    }
    cout << scores[0][N - 1];
    return 0;
}

 

 

今年的题目:

第二题也是关于回文的

第二题:

给一个字符串,每次可以移除其中一个字符,或者移除一个回文子串,求 全部移除所需最少次数

例如:14315.先移除3,再移除141,再移除5,得到最少次数3.

 

其实理解一下题意就会发现一模一样。

发布了108 篇原创文章 · 获赞 121 · 访问量 37万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览