剑指 Offer 48. 最长不含重复字符的子字符串
1、题目
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
2、题解
解法一:动态规划
动态规划步骤:
-
确定 dp 数组
设动态规划列表 dp ,dp[j] 代表以字符 s[j] 为结尾的 “最长不重复子字符串” 的长度。 -
确定递推公式
j - i : 表示 “最长不重复子字符串” 长度,用来不断更新
-
初始化
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。
动态规划步骤:
- 确定 dp 数组
int[] dp = new int[n];
,含义是存储质因子,从小到大,dp[i] 代表第 i+1 个丑数; - 确定递推公式
dp[i] = Math.min(next2, Math.min(next3, next5));
丑数只能是以上三种情况之一。 - 初始化
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];
}
}