zoukankan      html  css  js  c++  java
  • Leetcode 516 最长回文子序列

      动态规划的核心是找到解题路径中的重复子问题,避免重复计算。

      找出问题间的递归关系,用问题解决问题需要培养归纳的思维。

      问题定义的好坏直接影响到可以定位出的重叠子问题的多少,可以找出的重叠子问题越多,问题定义越好。

      下面是两种问题的定义,效率差距非常大。

      解法1,超时:

    public final int longestPalindromeSubseq(String s) {
            int re = 0;
            int len = s.length();
            int[][] cache = new int[len + 1][len + 1];
            Map<Character, Integer> map = new HashMap<Character, Integer>();
            for (int i = 0; i < s.length(); i++) {
                map.put(s.charAt(i), i);
            }
            for (int i = 0; i < s.length(); i++) {
                re = Math.max(re, longestPalindromeSubseq(s, i, len, cache, map));
            }
            return re;
        }
    
        /**
         * @Author Niuxy
         * @Date 2020/7/27 9:27 下午
         * @Description 求最长回文子序列
         * 固定头元素,区间寻找尾元素
         */
        private final int longestPalindromeSubseq(String s, int begin, int end, int[][] cache,
                                                  Map<Character, Integer> map) {
            if (begin > end) {
                return 0;
            }
            if (begin == end - 1) {
                return 1;
            }
            if (cache[begin][end] != 0) {
                return cache[begin][end];
            }
            //在 begin 与 end 之间找尾元素
            int endIn = begin;
            char beginChar = s.charAt(begin);
            int e;
            if (map.containsKey(beginChar) && (e = map.get(beginChar)) < end) {
                endIn = e;
            } else {
                for (int i = begin + 1; i < end; i++) {
                    if (s.charAt(begin) == s.charAt(i)) {
                        endIn = i;
                    }
                }
            }
            if (begin == endIn) {
                return 0;
            }
            //递归子序列
            int re = 0;
            for (int i = begin + 1; i < endIn; i++) {
                re = Math.max(re, longestPalindromeSubseq(s, i, endIn, cache, map));
            }
            re += 2;
            cache[begin][end] = re;
            return re;
        }

      解法2:

    /**
         * @Author Niuxy
         * @Date 2020/7/28 12:12 下午
         * @Description 对于分治问题的定义,为了维系问题间的关系,定义必须包含头元素与尾元素
         * 上一种方法固定一端在区间寻找另一端,在区间内寻找问题的递归结构
         * 换一种思路,每个元素只有两个状态,选择或者不选择
         * 尝试在这两个状态间切换,以此寻找问题间的递归关系
         */
        private final int longestPalindromeSubseq(String s, int begin, int end, int[][] cache) {
            if (begin == end) {
                return 1;
            }
            if (cache[begin][end] != 0) {
                return cache[begin][end];
            }
            int re = 0;
            //符合回文条件,首尾必选
            if (s.charAt(begin) == s.charAt(end)) {
                re = longestPalindromeSubseq(s, begin + 1, end - 1, cache) + 2;
            } else {
                //否则选一个,挑最长的
                re = Math.max(longestPalindromeSubseq(s, begin, end - 1, cache), longestPalindromeSubseq(s, begin + 1,
                        end, cache));
            }
            cache[begin][end] = re;
            return re;
        }
    
        public final int longestPalindromeSubseqDP(String s) {
            int len = s.length();
            return longestPalindromeSubseq(s, 0, len - 1, new int[len][len]);
        }

  • 相关阅读:
    2016孤独重视
    什么时候有空写一篇影评 《含泪活着》
    登录页面总结
    心跳机制
    心跳机制详解
    mysql数据库字符编码修改
    mysql20170404代码实现
    2017全面JAVA面试经历总结
    Oracle经典入门教程
    MySQL基础教程-绝对推荐
  • 原文地址:https://www.cnblogs.com/niuyourou/p/13390479.html
Copyright © 2011-2022 走看看