20230914刷题记录_链表、哈希表

20230914刷题记录
参考【代码随想录】来刷的。
关键词:链表、环形链表、哈希表

1 链表相交

面试题 02.07. 链表相交
力扣题目链接
easy
在这里插入图片描述
用于遍历长度较长的那个链表的指针要先移动。

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lengthA = 0;
        int lengthB = 0;
        ListNode p = headA;
        ListNode q = headB;
        while (p != null) {
            ++lengthA;
            p = p.next;
        }
        while (q != null) {
            ++lengthB;
            q = q.next;
        }

        p = headA;
        q = headB;
        if (lengthA > lengthB) 
            for (int i = 0; i < (lengthA - lengthB); i++) 
                p = p.next;
            
        else 
            for (int i = 0; i < (lengthB - lengthA); i++) 
                q = q.next;
        
        while (p != null) {
            if (p == q)
                return p;
            p = p.next;
            q = q.next;
        }
        return null;
    }
}

2 环形链表II

142.环形链表II
力扣题目链接
可以分解为两个问题:

  1. 是否存在环
  2. 找到环入口

2.1 是否存在环

使用快慢指针,slow、fast,slow一次移动一个结点,fast一次移动两个结点。
如果移动数次后,fast为空,那么不存在环。
如果slow与fast相遇,那么存在环。

2.2 找到环入口

假设从头结点到环形入口节点 的节点数为x。
环形入口节点到 fast指针与slow指针相遇节点 节点数为y。
从相遇节点 再到环形入口节点节点数为 z。
在这里插入图片描述
相遇时,
慢指针走过的结点数为
S s l o w = x + m ( y + z ) + y Sslow=x+m(y+z)+y Sslow=x+m(y+z)+y
其中m为快慢指针相遇时,慢指针走过的环的圈数。
快指针走过的结点数为
S f a s t = x + n ( y + z ) + y Sfast=x+n(y+z)+y Sfast=x+n(y+z)+y
其中n为快慢指针相遇时,快指针走过的环的圈数。
又快指针的速度是慢指针速度的两倍,花费的时间相同,故
S f a s t = 2 S s l o w Sfast=2Sslow Sfast=2Sslow

x + n ( y + z ) + y = 2 ( x + m ( y + z ) + y ) x+n(y+z)+y = 2(x+m(y+z)+y) x+n(y+z)+y=2(x+m(y+z)+y)
化简得
x = ( n − 2 m ) ( y + z ) − y x=(n-2m)(y+z)-y x=(n2m)(y+z)y
将x带入
S s l o w = x + m ( y + z ) + y Sslow=x+m(y+z)+y Sslow=x+m(y+z)+y

S s l o w = ( n − m ) ( y + z ) Sslow=(n-m)(y+z) Sslow=(nm)(y+z)
即当快慢指针相遇时,慢指针移动的总结点数为上式。
又慢指针移动的总结点数=慢指针在环外移动的结点数+慢指针在环内移动的结点数。
故快慢指针相遇时,慢指针在环内移动的结点数为
( n − m ) ( y + z ) − x (n-m)(y+z)-x (nm)(y+z)x
即慢指针再移动 x 个结点即可到达环入口。
因为再移动 x 个结点后,慢指针在环内移动的结点数为
( n − m ) ( y + z ) , (n-m)(y+z), (nm)(y+z)
即为环内结点数的整数倍。
故可让fast指向链表的头结点,让fast与slow同时开始移动,且fast与slow每次均移动一个结点,则fast必定会与slow在环入口处相遇。

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        try {
            do {
                fast = fast.next.next;
                slow = slow.next;
            } while (fast != slow);
        } catch (NullPointerException e) {
            return null;
        }

        fast = head;
        while (fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }

        return slow;
    }
}

3 有效的字母异位词

242.有效的字母异位词
力扣题目链接
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
如果 t 与 s 互为字母异位词,那么 t 中字母的出现次数必定与 s 中的相同。
可以用哈希表来记录每个字母的出现次数,因为从哈希表中取数据的操作是O(1)。
哈希表有两种实现方式:

  • java自带的hash表,HashSet、HashMap
  • 自己用数组实现

直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。

不要小瞧 这个耗时,在数据量大的情况,差距是很明显的。

优点缺点
自带实现方便速度比数组慢
用数组实现速度更快必须知道数组的长度,即最大数据的值
class Solution {
    public boolean isAnagram(String s, String t) {
        int[] record = new int[26];
        
        for (int i = 0; i < s.length(); i++) {
            record[s.charAt(i) - 'a']++;
        }
        for (int i = 0; i < t.length(); i++) {
            record[t.charAt(i) - 'a']--;
        }

        for (int i = 0; i < record.length; i++) {
            if (record[i] != 0)
                return false;
        }
        
        return true;
    }
}

4 两个数组的交集

349.两个数组的交集
力扣题目链接
步骤

  1. 将nums1中的数据存入hash1
  2. 遍历nums2,如果nums2中的数据也在hash1中,则将该数据存入hash2
  3. 遍历hash2,将符合条件的加入list
  4. 将list转为数组

注意将list转为数组的处理方式。

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        int[] hash1 = new int[1001];
        int[] hash2 = new int[1001];
        for (int n1: nums1) {
            hash1[n1] = 1;
        }
        for (int n2: nums2) {
            if (hash1[n2] == 1)
                hash2[n2] = 1;
        }

        List<Integer> resList = new ArrayList<>();
        for (int i = 0; i < hash2.length; i++) {
            if (hash2[i] > 0)
                resList.add(i);
        }
        
        return resList.stream().mapToInt(item -> item).toArray();
    }
}

5 两个数组的交集 II

350.两个数组的交集 II

力扣题目链接
跟上面的类似。

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        int[] hash1 = new int[1001];
        int[] hash2 = new int[1001];

        for (int n1: nums1)
            hash1[n1]++;
        for (int n2: nums2)
            hash2[n2]++;

        List<Integer> reList = new ArrayList<>();
        for (int i = 0; i < hash1.length; i++) {
            if (hash1[i] > 0 && hash2[i] > 0)
                for (int i1 = 0; i1 < Math.min(hash1[i], hash2[i]); i1++)
                    reList.add(i);
        }

        return reList.stream().mapToInt(x -> x).toArray();
    }
}

6 快乐数

力扣题目链接
两点

  1. 如何找出重复的结果?
    使用哈希表,取数据操作的时间复杂度为O(1)。
  2. 如何对int型数据的每一个进行处理?
    取余。
class Solution {
    public boolean isHappy(int n) {
        Set<Integer> set = new HashSet<>();
        while (n != 1 && !set.contains(n)) {
            set.add(n);
            n = getNextNumber(n);
        }
        return n == 1;
    }

    private int getNextNumber(int n) {
        int res = 0;
        while (n != 0) {
            int temp = n % 10;
            res += temp * temp;
            n /= 10;
        }
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值