leetcode word-break(Java)

leetcode题目

 word-break

题目描述

 * Given a string s and a dictionary of words dict, 
 * determine if s can be segmented into a space-separated sequence of one or more dictionary words.
 * 
 * For example, given
 * s ="leetcode",
 * dict =["leet", "code"].
 * Return true because "leetcode" can be segmented as"leet code".
 * 
 * 中文释义:
 * 把dict中的元素进行组合,可以重复使用,是否可以拼成s

思路

 * 1、求f(j) = s[0,j](j>=0)是否能被dict中的元素组合
 * 2、状态递推,求出s[0,i](i>j)是否能被dict中的元素组合,状态转移方程:f(i) = f(j) && f(j+1, i)  (j<i)
 * 3、最终求出f(sLen) = s [0, sLen]
 * 
 * 注意:
 * 1、初始为true f(0) = true
 * 2、初始状态数组大小为sLen+1
 * 3、结果返回数组的最后一个元素

动态规划简述

 * 1、什么是动态规划? 
 * 算法导论这本书是这样介绍这个算法的,动态规划与分治方法类似,都是通过组合子问题的解来来求解原问题的。
 * 再来了解一下什么是分治方法,以及这两者之间的差别,分治方法将问题划分为互不相交的子问题,递归的求解子问题,再将它们的解组合起来,求出原问题的解。
 * 而动态规划与之相反,动态规划应用与子问题重叠的情况,即不同的子问题具有公共的子子问题(子问题的求解是递归进行的,将其划分为更小的子子问题)。
 * 在这种情况下,分治方法会做许多不必要的工作,他会反复求解那些公共子子问题。而动态规划对于每一个子子问题只求解一次,将其解保存在一个表格里面,从而无需每次求解一个子子问题时都重新计算,避免了不必要的计算工作。 
 * 
 * 2、动态规划的应用场景: 
 * 动态规划方法一般用来求解最优化问题。这类问题可以有很多可行解,每个解都有一个值,我们希望找到具有最优值的解,我们称这样的解为问题的一个最优解,而不是最优解,因为可能有多个解都达到最优值。 
 *    我们解决动态规划问题一般分为四步: 
 *    1、定义一个状态,这是一个最优解的结构特征 
 *    2、进行状态递推,得到递推公式 
 *    3、进行初始化 
 *    4、返回结果 
 * 
 * 3、求解方式:
 * 动态规划算法的核心是记住已经求过的解,记住求解的方式有两种:
 * ①自顶向下的备忘录法 。计算目标值,计算出来后保存在缓存(可用数组)中。
 * ②自底向上。 先计算子问题,再由子问题计算父问题。

代码

package com.my.test.leco.dyncplanning;

import java.util.HashSet;
import java.util.Set;

/**
 * 题目:
 * word-break
 * 
 * 题目描述:
 * Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
 * For example, given
 * s ="leetcode",
 * dict =["leet", "code"].
 * Return true because "leetcode" can be segmented as"leet code".
 * 
 * 中文释义:
 * 把dict中的元素进行组合,可以重复使用,是否可以拼成s
 * 
 */
public class WordBreak
{
    
    /**
     * 什么是动态规划? 
     * 算法导论这本书是这样介绍这个算法的,动态规划与分治方法类似,都是通过组合子问题的解来来求解原问题的。
     * 再来了解一下什么是分治方法,以及这两者之间的差别,分治方法将问题划分为互不相交的子问题,递归的求解子问题,再将它们的解组合起来,求出原问题的解。
     * 而动态规划与之相反,动态规划应用与子问题重叠的情况,即不同的子问题具有公共的子子问题(子问题的求解是递归进行的,将其划分为更小的子子问题)。
     * 在这种情况下,分治方法会做许多不必要的工作,他会反复求解那些公共子子问题。而动态规划对于每一个子子问题只求解一次,将其解保存在一个表格里面,从而无需每次求解一个子子问题时都重新计算,避免了不必要的计算工作。 
     * 
     * 动态规划的应用场景: 
     * 动态规划方法一般用来求解最优化问题。这类问题可以有很多可行解,每个解都有一个值,我们希望找到具有最优值的解,我们称这样的解为问题的一个最优解,而不是最优解,因为可能有多个解都达到最优值。 
     *    我们解决动态规划问题一般分为四步: 
     *    1、定义一个状态,这是一个最优解的结构特征 
     *    2、进行状态递推,得到递推公式 
     *    3、进行初始化 
     *    4、返回结果 
     * 
     * 求解方式:
     * 动态规划算法的核心是记住已经求过的解,记住求解的方式有两种:
     * ①自顶向下的备忘录法 。计算目标值,计算出来后保存在缓存(可用数组)中。
     * ②自底向上。 先计算子问题,再由子问题计算父问题。
     */
    
    /**
     * wordBreak<br>
     * 
     * 思路:
     * 1、求f(j) = s[0,j](j>=0)是否能被dict中的元素组合
     * 2、状态递推,求出s[0,i](i>j)是否能被dict中的元素组合,状态转移方程:f(i) = f(j) && f(j+1, i)  (j<i)
     * 3、最终求出f(sLen) = s [0, sLen]
     * 
     * 注意:
     * 1、初始为true f(0) = true
     * 2、初始状态数组大小为sLen+1
     * 3、结果返回数组的最后一个元素
     * 
     * @param s 字符串
     * @param dict 字符串组合
     * @return
     */
    public boolean wordBreak(String s, Set<String> dict) {
        if (s == null || s.isEmpty() || dict == null || dict.isEmpty()) {
            return false;
        }
        // 初始化存储状态值的数组
        int len = s.length();
        boolean [] states = new boolean[len + 1];
        states[0] = true;
        // 递推求解
        for (int i=1; i<=len; i++) {
            // 递推求解f(i)
            for (int j=0; j<i; j++) {
                // f(j) && f(j+1, i) 找到一个为true即可
                if (states[j] && dict.contains(s.substring(j, i))) {
                    states[i] = true;
                    break;
                }
            }
        }
        return states[len];
    }
    
    public static void main(String[] args)
    {
        String s = "leetcode";
        Set<String> dict = new HashSet<>();
        dict.add("leet");
        dict.add("code");
        System.out.println(new WordBreak().wordBreak(s, dict));
    }

}

 
 
 
 
参考:
【算法】详解动态规划
【算法】-动态规划 Dynamic Programming–从菜鸟到老鸟

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值