0406-算法复盘-判断链表中是否有环、链表中环的入口、两数之和、找到字符串的最长无重复字符子串、 括号序列、二分查找

本文介绍了数据结构中链表的常见问题,包括判断链表中是否存在环以及找到环的入口。此外,还讨论了如何利用哈希集合和快慢指针解决这些问题。接着,我们探讨了使用哈希表进行两数之和的查找,以及寻找字符串最长无重复字符子串的方法。最后,展示了如何通过栈来验证括号序列的有效性以及在有重复元素的升序数组中进行二分查找。这些算法在实际编程中具有广泛的应用。
摘要由CSDN通过智能技术生成

1. 判断链表中是否有环

非开空间复杂度O(1)解法:直接使用Set容器,如果有重复节点值则判断当前有环,这个思路比较简单明确

O(1)解法:使用两个指针,一个一次走两格快指针,一个慢一次走一格慢指针。在有环的情况下因为慢指针是一个一个走的所以快慢指针一定会相遇。有了这思路便可快速的判断出是否有环

public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null) return false;
        ListNode low = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){
            low = low.next;
            fast = fast.next.next;
            if(low == fast){
                return true;
            }
        }
        return false;
    }
}

2.链表中环的入口

这个题目是上题的变种题,使用上面的思路一 很简单的可以找出链表中环的入口,但是这样的空间复杂度是大的

下面摘抄至Lettcode上的算法题解

如下图所示,X,Y,Z分别为链表起始位置,环开始位置和两指针相遇位置,则根据快指针速度为慢指针速度的两倍,可以得出:

2*(a + b) = a + b + n * (b + c);即

a=(n - 1) * b + n * c = (n - 1)(b + c) +c;

注意到b+c恰好为环的长度,故可以推出,如将此时两指针分别放在起始位置和相遇位置,并以相同速度前进,当一个指针走完距离a时,另一个指针恰好走出 绕环n-1圈加上c的距离。

故两指针会在环开始位置相遇。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j9KZfiOx-1617769634106)(http://cdn.noteblogs.cn/122270_1439340467801_QQ%E6%88%AA%E5%9B%BE20150812084712.jpg)]

set解法

import java.util.*;
public class Solution {
    public ListNode detectCycle(ListNode head) {
        Set<ListNode> set = new HashSet<>();
        if(head == null)    return null;
        while(head != null){
            if(set.contains(head)){
                  return head;
            }
            set.add(head);
            head = head.next;
        }
        return null;
    }
}

快慢指针解法,TODO

3. 两数之和

给出一个整数数组,请在数组中找出两个加起来等于目标值的数,

你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的

假设给出的数组中只存在唯一解

例如:

给出的数组为 {20, 70, 110, 150},目标值为90
输出 index1=1, index2=2

思路:还是使用Set。解决普通解法两次循环问题,一次遍历即可。遍历nums[i]的时候判断target -nums[i]是否在set容器中,如果在说明已经找到了这两个数,如果不在容器中则将nums[i]加入set容器中

public class Solution {
    /**
     *
     * @param numbers int整型一维数组
     * @param target int整型
     * @return int整型一维数组
     */
    public int[] twoSum (int[] numbers, int target) {
        int[] res = new int[2];
        // write code here
        Map<Integer, Integer> map = new HashMap<>();
        map.put(numbers[0], 0);
        for(int i = 1; i < numbers.length; i++){
            if(map.containsKey(target - numbers[i])){
                res[0] = map.get(target - numbers[i]) + 1;
                res[1] = i + 1;
            }
            map.put(numbers[i], i);
        }
        return res;
    }
}

4. 找到字符串的最长无重复字符子串

使用一个队列维护一个窗口

public class Solution {
    /**
     *
     * @param arr int整型一维数组 the array
     * @return int整型
     */
    public int maxLength (int[] arr) {
        // write code here
        Deque<Integer> q = new LinkedList<>();
        int res = 0;
        for(int i = 0;i < arr.length;i++){
            // 注意这个while 如果发现包含应该要将窗口内的元素都移除
            while(q.contains(arr[i])){
                q.pollFirst();
            }
            q.offerLast(arr[i]);
            res = Math.max(res, q.size());
        }
        return res;
    }
}

5. 括号序列

简单的思路:使用栈,如果遇到’(‘则加入’)‘到栈中,相反如果遇到’)'则弹出栈判断是否相等,其余两个字符也是一样的

public class Solution {
    /**
     *
     * @param s string字符串
     * @return bool布尔型
     */
    public boolean isValid (String s) {
        // write code here
        Stack<Character> stack = new Stack<>();
        for(int i = 0;i < s.length();i++){
            if(s.charAt(i) == '('){
                stack.push(')');
                continue;
            }
            else if(s.charAt(i) == '['){
                stack.push(']');
                continue;
            }
            else if(s.charAt(i) == '{') {
                stack.push('}');
                continue;
            }
            else{
                if(stack.isEmpty() || stack.pop() != s.charAt(i)) return false;
            }
        }
        return stack.isEmpty();
    }
}

6. 二分查找

请实现有重复数字的升序数组的二分查找

给定一个 元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

题目的关键点在于重复数字,对于升序序列来说可以使用二分查找,但是因为有重复元素,所以应该要向左逼近

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 如果目标值存在返回下标,否则返回 -1
     * @param nums int整型一维数组
     * @param target int整型
     * @return int整型
     */
    public int search (int[] nums, int target) {
        // write code here
        if(nums == null || nums.length == 0)    return -1;
        int left = 0, right = nums.length - 1;
        while(left < right){
            int mid = (left + right) >> 1;
            if(nums[mid] < target){
                left = mid + 1;
            }else{
                //向左逼近
                right = mid;
            }
        }
        return nums[left] == target ? left : -1;
    }
}

target){
left = mid + 1;
}else{
//向左逼近
right = mid;
}
}
return nums[left] == target ? left : -1;
}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值