阿里笔试第二题 最长旋律

题目大概是这样的,小明在学旋律,每段旋律都可以用字符串来表示,并且旋律的每个
字符的ASCALL码递增的
比如以下4段旋律 :
aaa
bcd
bcdef
zzz
现在就是要求,小明能够吧这些旋律拼接起来组成最长的旋律。
比如上述例子输出 11 最长的旋律为 aaabcdefzzz
package com.alibaba.interview;

import java.util.*;

/**
 * 阿里笔试第2题,最长旋律
 *
 * @author wuddong
 * @date 2020-03-20 08:48
 */
public class Main {
    /**
     * 动态保存全部最大值
     */
    private int maxLength = 0;
    /**
     * 后缀和,减枝的时候用到
     */
    private int[] lengthLeft;
    /**
     * 旋律,由输入满足每个字符串递增
     */
    private List<String> melodies;

    /**
     * memo solver max length
     */
    private int memoMaxLength = 0;

    public Main(List<String> melodies) {
        melodies.sort(String::compareTo);
        this.melodies = melodies;
        lengthLeft = new int[melodies.size() + 1];
        // 进行排序, 时间复杂度O(nlog(n))
        melodies.sort(String::compareTo);
        for (int i = melodies.size() - 1; i >= 0; i--) {
            lengthLeft[i] = melodies.get(i).length() + lengthLeft[i + 1];
        }
    }

    private int memoSolver() {
        return memoSolver(new Integer[melodies.size()], 0);
    }

    /**
     * 自定向下记忆法
     * 时间复杂度O(N^2)
     */
    private int memoSolver(Integer[] memo, int start) {
        if (start == melodies.size() - 1) {
            memo[start] = melodies.get(start).length();
        }
        if (memo[start] != null) {
            return memo[start];
        }
        String curString = melodies.get(start);
        int curLen = curString.length();
        for (int i = start + 1; i < melodies.size(); i++) {
            int next = memoSolver(memo, i);
            if (curString.charAt(curString.length() - 1) <= melodies.get(i).charAt(0)) {
                memoMaxLength = Math.max(memoMaxLength, curLen + next);
            }
        }
        memo[start] = memoMaxLength;
        return memoMaxLength;
    }


    /**
     * 动态规划解决该问题,时间复杂度O(N^2)
     * 空间复杂度O(N)
     *
     * @return maxLengthOfCombineMelodyLength
     */
    private int dynamicSolver() {
        String[] mel = new String[melodies.size()];
        melodies.toArray(mel);
        int[] dp = new int[mel.length];
        for (int j = mel.length - 1; j >= 0; j--) {
            for (int i = j; i < mel.length; i++) {
                if (i == j) {
                    dp[j] = mel[j].length();
                } else if (mel[j].charAt(mel[j].length() - 1) <= mel[i].charAt(0)) {
                    dp[j] = Math.max(dp[j], mel[j].length() + dp[i]);
                }
            }
        }
        return dp[0];
    }

    /**
     * 递归回溯解决问题
     * 时间复杂度 2^N
     *
     * @return maxLengthOfCombineMelodyLength
     */
    public int solve() {
        // 减枝法
        nextMelody(melodies, 0, 0);
        dynamicSolver();
        // 动态规划
        if (dynamicSolver() != maxLength) {
            throw new RuntimeException("dynamicSolver 和 减枝法 解法不一致");
        }
        // 记忆法
        if (memoSolver() != maxLength) {
            System.out.println(memoMaxLength);
            throw new RuntimeException("memoSolver 和 减枝法 不一样");
        }
        return maxLength;

    }

    private void nextMelody(List<String> melodies, int n, int curLength) {
        if (n == melodies.size()) {
            return;
        }
        String curMelody = melodies.get(n);
        curLength += curMelody.length();
        maxLength = Math.max(maxLength, curLength);
        char curMelodyLastChar = curMelody.charAt(curMelody.length() - 1);
        for (int i = n + 1; i < melodies.size(); i++) {
            char nextMelodyFirstChar = melodies.get(i).charAt(0);
            int cmp = curMelodyLastChar - nextMelodyFirstChar;
            if (cmp <= 0 && curLength + lengthLeft[i] > maxLength) {
                nextMelody(melodies, i, curLength);
            }
        }
    }


    /**
     * 执行入口
     */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        List<String> melodies = new ArrayList<>();
        int n = sc.nextInt();
        for (int i = 0; i <= n; i++) {
            String input = sc.nextLine();
            if (input.length() == 0) {
                continue;
            }
            melodies.add(input);
        }
        Main mainSolver = new Main(melodies);
        System.out.println(mainSolver.solve());
    }

    /**
     * 临场时想到的方法 解法出错
     * 不通过
     */
    private static int maxLengthOfMelodies(List<String> melodies) {
        melodies.sort(String::compareTo);
        StringBuilder sb = new StringBuilder();
        melodies.forEach(sb::append);
        String melodiesConcat = sb.toString();
        System.out.println(melodiesConcat);
        // 最长上升子序列
        // 处理相同的
        int[] dp = new int[melodiesConcat.length()];
        int len = 0;
        int skip = 0;
        int last = -1;
        for (char c : melodiesConcat.toCharArray()) {
            int cur = c - '0';
            if (last == cur) {
                skip++;
                continue;
            }
            int i = Arrays.binarySearch(dp, 0, len, cur);
            if (i < 0) {
                // 新单词
                i = -(i + 1);
            }
            if (i == len) {
                len++;
            }
            dp[i] = cur;
            last = cur;
        }
        return len + skip;
    }
}

希望上述分享,能够给大家带来一点新的思路,接下来的笔试顺利,早点拿到心仪的offer!
欢迎各位留言讨论~

#2020阿里第一场笔试##笔试题目##阿里巴巴#
全部评论
向大佬看齐
2 回复 分享
发布于 2020-03-20 14:02
def solve(s):     dp = [0 for i in range(len(s))]     dp[0] = len(s[0])     for i in range(0,len(s)):         for j in range(i + 1, len(s)):             if s[j][0] > s[i][-1] and dp[i] + len(s[j]) > dp[j]:                 dp[j] = dp[i] + len(s[j])     return dp[len(s) - 1] dp     O(n^2),大家看看
1 回复 分享
发布于 2020-03-20 15:47
点赞 回复 分享
发布于 2020-03-20 15:47
盒马校招,欢迎砸简历
点赞 回复 分享
发布于 2020-03-20 15:53
2020年阿里巴巴钉钉实习生招聘火热进行中!每一个即将加入钉钉的远航者们,钉钉的未来由你定义,更好的世界,更好的你!欢迎扫码推荐或者简历发送邮箱:qiuting.lqt@alibaba-inc.com
点赞 回复 分享
发布于 2020-03-20 15:56
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6 + 10; int dp[26][26], n; char str[maxn]; void update() {     int e1 = str[0] - 'a';     int e2 = str[strlen(str)-1] - 'a';     int len = strlen(str);     for(int i = 0;i <= e1;i++)         for(int j = 25;j >= e2;j--)         {             if(e1 == e2 && dp[e1][e2] > 0) // 插入                 dp[i][j] = dp[i][j] + len;             else   // 拼接                 dp[i][j] = max(dp[i][j], dp[i][e1] + len + dp[e2][j]);         } } int main() {     scanf("%d", &n);     for(int i = 0;i < n;i++)     {         scanf("%s", str);         update();     }     printf("%d\n", dp[0][25]); } 时间复杂度O(n)
点赞 回复 分享
发布于 2020-03-22 20:11
这题感觉像0-1背包,先将每个序列按首字母排序,每个序列可以选可以不选,选的话还要判断是否递增,然后求出最大的收益,也就是最长的组合。
点赞 回复 分享
发布于 2020-03-23 16:59

相关推荐

安静的垂耳兔在泡澡:ks已经第八次投递了,它起码挂了还让你再投,不错了
点赞 评论 收藏
分享
评论
20
56
分享
牛客网
牛客企业服务