Leetcode3. 无重复字符的最长子串
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情。
❤️欢迎订阅java厂长《LeetCode每日一题》 ❤️
1、题目📑
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
实例1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
实例2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
实例3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104s由英文字母、数字、符号和空格组成
2、思路🧠
方法一:滑动窗口(利用循环去重)
- 定义一个set集合来模拟字符串的窗口,left表示窗口的左端,right表示窗口的右端。
- 在移动的过程中保证左端一直在左侧
- 如果窗口中包含当前元素,说明出现了重复,把窗口最左端的给移除掉,直到窗口不包含当前元素。
- 窗口不出现重复元素,不断右移,记录窗口的最大长度。
方法二:滑动窗口(利用Map去重)
- left表示窗口的左端,right表示窗口的右端
- 定义一个 map 数据结构存储 (k, v),其中 key 值为窗口右端的字符,value 值为右端字符位置的下一个位置,加 1 表示从字符位置后一个才开始不重复。
- 窗口的右端向右移动,在right遍历的过程中,窗口【left,right】会出现相同字符的情形,将字符作为 key 值,获取其 value 值,并更新 left 左端的变化,以保证区间不会出现重复的字符。
- 同时使用
maxLength来记录窗口的最大长度。
废话少说~~~~~上代码!
3、代码👨💻
第一次commit AC
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() == 0) return 0;
if(s.length() == 1) return 1;
Set<Character> set = new HashSet<>();
int left = 0, right = 0,maxLength = 0;
while (right < s.length()) {
// 如果窗口中包含当前元素,说明出现了重复,
// 把窗口最左端的给移除掉,直到窗口不包含当前元素即可
while(set.contains(s.charAt(right)))
set.remove(s.charAt(left++));
//窗口不出现重复元素,右移
set.add(s.charAt(right++));
//记录窗口的最大长度
maxLength = Math.max(maxLength, right - left);
}
return maxLength;
}
}
时间复杂度:O(N) N为字符串 s 的长度
空间复杂度:O(1)
第二次commit AC
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() == 0) return 0;
if(s.length() == 1) return 1;
Map<Character, Integer> map = new HashMap<>();
int left = 0, right = 0,maxLength = 0;
while (right < s.length()) {
if(map.containsKey(s.charAt(right))) {
left = Math.max(left, map.get(s.charAt(right)));
}
map.put(s.charAt(right), right + 1);
maxLength = Math.max(maxLength, right - left + 1);
right ++;
}
return maxLength;
}
}
时间复杂度:O(N) N为字符串 s 的长度
空间复杂度:O(1)
4、总结
该题目的对大根堆的结构进行灵活的运用,并且能够想到对最大数减半操作收益是最大的。
自建堆模板:
package com.cz.Sort;
import java.util.Arrays;
/**
* @ProjectName: 大根堆
* @Package: com.cz.Sort
* @ClassName: Heap
* @Author: 张晟睿
* @Date: 2022/3/17 20:23
* @Version: 1.0
*/
public class Heap {
public static class MyMaxheap {
private int heap[];
private final int limit;
private int heapSize;
public MyMaxheap(int limit) {
heap = new int [limit];
this.limit = limit;
heapSize = 0;
}
public boolean isEmpty() {
return heapSize == 0;
}
public boolean isFull() {
return heapSize == limit;
}
public void push(int value){
if (isFull())
throw new RuntimeException("heap is full");
heap[heapSize] = value;
heapInsert(heap, heapSize++);
}
public int pop(){
int ans = heap[0];
swap(heap, 0 , --heapSize);
heapify(heap, 0, heapSize);
return ans;
}
private void heapInsert(int[] arr, int index) {
//当前index和父亲比较 当前index比其父亲大,交换
//当前来的值和他的父亲节点比较
//结束条件
//arr[index] 不比 arr[index父] 大的时候
//index = 0 来到了顶端
while(arr[index] > arr[(index - 1) / 2]) {
swap(arr, index , (index - 1) / 2);
index = (index - 1) / 2;
}
}
/**
*
* @param arr 需要调整为大根堆的数组
* @param index 从index位置往下看,不断的下沉 停止条件:当前所有的孩子都不比我大,没有孩子了
* @param heapSize 堆的大小
*/
private void heapify(int[] arr, int index, int heapSize) {
int left = 2 * index ^ 1; //左孩子的下标
while(left < heapSize) { //左孩子下标不越界,即有孩子存在
//左右两个孩子,谁大把谁给largest
//右孩子胜出的情况下 ->1.有右孩子 2.有孩子的值比左孩子的值大
//否则,就是左孩子胜出
// 右孩子胜出 left + 1 < heapSize 右孩子不越界 arr[left + 1] > arr[left] 右孩子的值大于左孩子的值
int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
//largest两个孩子中最大孩子的下标
//最大孩子的值和父亲的值进行pk 谁大把谁的下标给largest
largest = arr[largest] > arr[index] ? largest : index;
//两个孩子都pk不过父节点,此时不用下沉了
if(largest == index) break;
//largest,index交换
swap(arr, largest, index);
//index继续往下沉,继续找下一个左孩子
index = largest;
left = (2 * index) ^ 1;
}
}
public void swap(int arr[], int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
public static void main(String[] args) {
MyMaxheap mmp = new MyMaxheap(10);
// for (int i = 0; i < 1000; i++) {
// if (mmp.isFull()) break;
// mmp.push((int)(Math.random() * 100));
// }
// mmp.push(1);
// mmp.push(3);
// mmp.push(6);
// mmp.push(2);
// mmp.push(5);
// mmp.push(9);
// System.out.println(Arrays.toString(mmp.heap));
// System.out.println(mmp.pop());
int arr[] = new int[]{1,3,6,2,5,9};
for (int i = arr.length - 1; i >= 0; i--) {
mmp.heapify(arr, i , arr.length);
}
}
}
❤️来自专栏《LeetCode基础算法题》欢迎订阅❤️
厂长写博客目的初衷很简单,希望大家在学习的过程中少走弯路,多学一些东西,对自己有帮助的留下你的赞赞👍或者关注➕都是对我最大的支持,你的关注和点赞给厂长每天更文的动力。
对文章其中一部分不理解,都可以评论区回复我,我们来一起讨论,共同学习,一起进步!