剑指 Offer 48. 最长不含重复字符的子字符串 剑指 Offer 49. 丑数

剑指 Offer 48. 最长不含重复字符的子字符串

1、题目

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
在这里插入图片描述

2、题解

解法一:动态规划
动态规划步骤:

  1. 确定 dp 数组
    设动态规划列表 dp ,dp[j] 代表以字符 s[j] 为结尾的 “最长不重复子字符串” 的长度。

  2. 确定递推公式
    j - i : 表示 “最长不重复子字符串” 长度,用来不断更新
    在这里插入图片描述
    在这里插入图片描述

  3. 初始化
    tmp = 0

解法二:滑动窗口

我们使用两个指针,一个i一个j,最开始的时候i和j指向第一个元素,然后i往后移,把扫描过的元素都放到map中,如果i扫描过的元素没有重复的就一直往后移,顺便记录一下最大值max,如果i扫描过的元素有重复的,就改变j的位置
在这里插入图片描述
在这里插入图片描述

3、代码

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dic = new HashMap<>();
        int res = 0, tmp = 0;
        for(int j = 0; j < s.length(); j++) {
            int i = dic.getOrDefault(s.charAt(j), -1); // 获取索引 i
            dic.put(s.charAt(j), j); // 更新哈希表
            tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j]
            res = Math.max(res, tmp); // max(dp[j - 1], dp[j])
        }
        return res;

    }
}

解法二:滑动窗口

class Solution {
    public int lengthOfLongestSubstring(String s) {
     
        Map<Character, Integer> dic = new HashMap<>();
        int max = 0;
        for(int i = 0, j = 0;i < s.length();i++){
            if(dic.containsKey(s.charAt(i))){
                j = Math.max(j, dic.get(s.charAt(i)) + 1);
            }
            dic.put(s.charAt(i), i);
            max = Math.max(max, i - j + 1);
        }
        return max;

    }
}

剑指 Offer 49. 丑数

1、题目

我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
在这里插入图片描述

2、题解

解法一: 暴力解

首先,理解什么是质因子,所谓一个数 m 是另一个数 n 的因子,是指 n 能被 m 整除,也就是说 n % m == 0。根据丑数的定义,丑数只能被2、3、5整除。也就是说,一个数能被 2 整除,那就连续连续除以 2,能被 3 整除,那就连续除以 3,能被 5 整除,那就连续除以 5 。如果最后得到的是 1 ,那么这个数就是丑数,否则不是。

因此很容易得到一种简单的解法,暴力解,看代码中部分(超时)。

解法二: 动态规划

正向因式分解不好做(超时),但反过来就好做了。题目的条件就从,只包含质因子 2、3 和 5 的数称作丑数,变成了,一个丑数可以通过另一个丑数 * 2 、* 3 、 * 5 得到,同时第一个丑数是1。
在这里插入图片描述

动态规划步骤:

  1. 确定 dp 数组
    int[] dp = new int[n];,含义是存储质因子,从小到大,dp[i] 代表第 i+1 个丑数;
  2. 确定递推公式
    dp[i] = Math.min(next2, Math.min(next3, next5)); 丑数只能是以上三种情况之一。
  3. 初始化
    dp[0] = 1; 1 就是质因子

3、代码

法一:暴力解

class Solution {
    public int nthUglyNumber(int n) {
        if(n == 1) return 1;
        int count = 1;
        int res = 0;
        for(int i = 2;i < Integer.MAX_VALUE;i++){ 
            if(isUgly(i)){
                count++;
            }
            if(count == n){
                res = i;
                break;
            }
        }
        return res;
    }

    public boolean isUgly(int num){
        while(num % 2 == 0) num /= 2;
        while(num % 3 == 0) num /= 3;
        while(num % 5 == 0) num /= 5;
        if(num == 1) return true;
        return false;
    }
}

法二:动态规划

class Solution {
    public int nthUglyNumber(int n) {
        int[] dp = new int[n];
        int id2 = 0, id3 = 0,id5 = 0;
        dp[0] = 1;
        
        for(int i = 1;i < n;i++){
            int next2 = dp[id2] * 2, next3 = dp[id3] * 3, next5 = dp[id5] * 5;
            dp[i] = Math.min(next2, Math.min(next3, next5));
            if(dp[i] == next2){
                id2++;
            }
            if(dp[i] == next3){
                id3++;
            }
            if(dp[i] == next5){
                id5++;
            }
        }
        return dp[n - 1];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值