3. 无重复字符的最长子串 4. 寻找两个正序数组的中位数 java

3. 无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例 4:

输入: s = ""
输出: 0

给一个序列,找答案。考虑怎么把所有情况枚举到。

双指针(索引)问题,要看单调性。所谓的单调性,指 双指针 单向移动。本题中为 j 和 i 都是往右边移动。

 j i 之间是此时最长无重复字符子串。之后 i 再往右移动。

有反证法可知  j` 只能为 j 或者出现在 j 的右边。每个指针只会从左往右走,走 n 次。 O(n)

 用 hashmap来维护 ij 子串中每个字符出现的次数。

 

import java.util.HashMap;
import java.util.Map;
public class Solution {
    public int lengthOfLongestSubstring(String s) {
        //map <字符串s中的字符,该字符在ij子串中出现的次数>
        Map<Character, Integer> map = new HashMap<>();
        //res 记录 曾经扫描到的最长子串的长度
        int res = 0;
        //i,j 相当于双指针,i到j 之间维护的是 无重复最长子串
        //先移i,后移j 。j在左,i在右。 ij子串
        for(int i = 0, j = 0; i < s.length(); i++){
            char a = s.charAt(i);
            if(map.containsKey(a)){
                map.put(a, map.get(a)+1);
            }else{
                map.put(a, 1);
            }
            /**
             * 当put进来后,发现ij子串中当前字符 a=s.charAt(i) 重复了,
             * 即 map中当前字符对应的value 大于1。put进来后,如果有重复字符,肯定是 a=s.charAt(i) 重复了。
             * 就需要重新调整ij之间的子串。
             * 调整方法为:
             * 移动j指针,逐个给map中对应字符的出现次数 -1,直到当前重复字符的出现次数为 1.
             * map的字符出现的次数为0,代表 ij子串中没有这个字符。
             */
            while(map.get(a) > 1){
                char b = s.charAt(j++);
                map.put(b, map.get(b) -1);
            }
            //更新res的值
            res = Math.max(res, i-j +1);
        }
        return res;
    }
}

4. 寻找两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

import java.util.HashMap;
import java.util.Map;
public class Solution {
    /**
     * 解题心得:做算法题要 画图,要草稿纸。举几个例子,涵盖一下各种情况,到时候,写的时候心里有数。
     *
     * 牢记 本题中,这两个数组是有序数组
     */
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        //计算 一共有多少个数,判断奇偶
        int tot = nums1.length + nums2.length;

        if(tot % 2 == 0){
            //偶数个数,找一个 左,一个 右
            int left = find(nums1, 0, nums2, 0, tot / 2);
            int right = find(nums1, 0, nums2, 0, tot / 2 +1);

            return (left + right) / 2.0;
        }else {
            //奇数个数,找 最中间的那个数
            return find(nums1, 0, nums2, 0, tot / 2 + 1);
        }
    }
    // nums1 从start1 索引开始,nums2 从start2 索引开始, 寻找这两个了数组中的第 k 大的数。(有序数组)
    private int find(int[] nums1, int start1, int[] nums2, int start2, int k) {
        //保证 nums1 短一点,如果 nums1比nums2 长,则交换位置。
        //规避 特殊情况:nums1 比 nums2 长
        if(nums1.length - start1 > nums2.length - start2){
            return find(nums2, start2, nums1, start1, k);
        }
        //边界1
        if(k == 1){
            if(nums1.length == start1){
                return nums2[start2];
            }else {
                return Math.min(nums1[start1], nums2[start2]);
            }
        }
        //边界2
        //当nums1 的长度等于 start1 的时候, 说明 把nums1 排除完了。
        if (nums1.length == start1){
            //寻找第 k 个数,k从1开始
            return nums2[start2 + k -1];
        }
        //Math.min 规避特殊情况:nums1 很短,比如只有一个元素
        int si = Math.min((int) nums1.length, start1 + k/2);
        int sj = start2+k - k/2;
        //si 是 从第一个数(start1)开始数,(第一个,第二个,...,)第 k/2 个数的编号,但对应数组的索引 为 si -1
        if(nums1[si - 1] > nums2[sj - 1]){
            return find(nums1, start1, nums2, sj, k - (sj - start2));
        }else{
            return find(nums1, si, nums2, start2, k - (si - start1));
        }

    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可持续化发展

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值