Leetcode 1405 最长快乐字符串 穷举与贪心

 

  题目被 leetcode 归类为动态规划,苦思冥想,没有找到合适的问题定义。

  决定首先穷举,借以理解解空间的结构。穷举解法:

复制代码
/**
     * @Author Niuxy
     * @Date 2020/7/20 11:17 下午
     * @Description 穷举
     */
    String longestStr = "";

    public String longestDiverseString(int a, int b, int c) {
        longest(a, b, c, "");
        return longestStr;
    }

    public final void longest(int a, int b, int c, String s) {
        longestStr = s.length() > longestStr.length() ? s : longestStr;
        if (a == 0 && b == 0 && c == 0) {
            return;
        }
        if (a > 0 && canInsert('a', s)) {
            longest(a - 1, b, c, s + "a");
        }
        if (b > 0 && canInsert('b', s)) {
            longest(a, b - 1, c, s + "b");
        }
        if (c > 0 && canInsert('c', s)) {
            longest(a, b, c - 1, s + "c");
        }
    }

    private final boolean canInsert(char ch, String s) {
        int length = s.length();
        if (length < 2) {
            return true;
        }
        char char0;
        if ((char0 = s.charAt(length - 1)) == s.charAt(length - 2)) {
            if (char0 == ch) {
                return false;
            }
        }
        return true;
    }
复制代码

  穷举函数就像一把散弹枪,在每个节点将所有可能性散射出去。直到三个元素都用完或者不可继续拼接,将结果数组进行记录,取全局最大值。

    明显的,要从所有可能的组合中找最长的组合,问题的定义没有最优子结构性质。

  D(a,b,c) 的定义不能是返回最长序列,上层问题无法根据该结果得出上层问题的最优解。

  D(a,b,c) 的定义只能是尝试所有可能的路径,上层问题基于该结果拓展出本层的所有可能的路径,从中取最优值。

    穷举路径进行搜索的函数没有建立缓存的必要,因为每条路径只会尝试一次。

      这样避免重复计算的路就行不通了。

  只能从另一个方向,避免无效计算来提升效率。

  凭直觉,想要结果字符串最长,应该最先将存量最多的元素拼入字符串,用次多的元素分割最多的元素。

  因为剩余元素中最多的元素越少,剩余元素可以组成的字符串也越长。

  贪心解法:

复制代码
    class CharAndNum implements Comparable {
        char ch;
        int count;

        CharAndNum(char ch, int count) {
            this.ch = ch;
            this.count = count;
        }

        @Override
        public int compareTo(Object o) {
            CharAndNum other = (CharAndNum) o;
            return other.count-count;
        }
    }

    public String longestDiverseString1(int a, int b, int c) {
        CharAndNum[] chars = new CharAndNum[]{
                new CharAndNum('a', a),
                new CharAndNum('b', b),
                new CharAndNum('c', c)
        };
        StringBuilder sb = new StringBuilder();
        while (true) {
            System.out.println(sb.toString());
            Arrays.sort(chars);
            if (isEnd(chars, sb)) {
                break;
            }
            if (canInsert(sb, chars[0].ch)) {
                sb.append(chars[0].ch);
                chars[0].count--;
            } else if (chars[1].count > 0) {
                sb.append(chars[1].ch);
                chars[1].count--;
            }
        }
        return sb.toString();
    }

    private final boolean isEnd(CharAndNum[] chars, StringBuilder sb) {
        if (chars[0].count == 0) {
            return true;
        }
        if (!canInsert(sb, chars[0].ch)) {
            if (chars[1].count == 0) {
                return true;
            }
        }
        return false;
    }

    private boolean canInsert(StringBuilder sb, char ch) {
        int length = sb.length();
        if (length < 2) {
            return true;
        }
        char pre;
        if ((pre = sb.charAt(length - 1)) == sb.charAt(length - 2)) {
            if (pre == ch) {
                return false;
            }
        }
        return true;
    }
复制代码

 

posted @   牛有肉  阅读(350)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示