Leetcode
刷题记录,第一题涉及哈希表,第二题涉及链表,
两数之和
题目描述
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
1 | 输入:nums = [2,7,11,15], target = 9 |
示例 2:
1 | 输入:nums = [3,2,4], target = 6 |
示例 3:
1 | 输入:nums = [3,3], target = 6 |
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
- 只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2)
的算法吗?
题目解法
常规解法
1 | class Solution { |
1.这里注意11行有可能找不到对应的数组下标,此时return new int[0]
new int[0]
是在 Java 中创建一个新的整数数组,但这个数组的长度为0。这意味着这个数组不包含任何元素。虽然这个数组看起来可能没什么用,但在某些情况下,它可以作为一个有效的非空对象返回,以避免返回 null 并可能导致NullPointerException
。这是一种编程技巧,用于处理可能没有数据返回的情况。总的来说,new int[0]
创建了一个空的整数数组。
2.还有7行返回两个数组下标的方法:return new int []{i,j}
3.length
是属性,不是方法。直接int length = nums.length
即可,无需加括号。
哈希表
1 | class Solution { |
在哈希表中,
containsKey
方法的平均时间复杂度是O(1),这意味着无论哈希表的大小如何,查找一个键的时间都是常数。这是因为哈希表使用哈希函数将键映射到一个特定的桶,然后在该桶中查找键,而桶的数量通常是固定的。然而,这只是平均情况。在最坏的情况下,如果所有的键都哈希到同一个桶,那么查找一个键的时间复杂度将是O(n),其中n是哈希表中键的数量。但是,如果哈希函数设计得好,并且键的分布是均匀的,那么这种情况是非常罕见的。
所以,当我们说
containsKey
方法的时间复杂度是O(1),我们是指在平均情况下。而在你的代码中,你遍历了数组一次,每次调用containsKey
方法一次,所以总的时间复杂度是O(n)。
比如输入数组是输入:nums = [2,7,11,15], target = 9
第一步,利用Map<Integer,Integer> hashtable = new HashMap<Integer,Integer>()
创建了一个空的HashMap
。
第二步,执行循环,当i = 0
时,哈希表中显然没有Ke y
值为9 - 2 = 7
的桶,所以,执行hashtable.put(nums[i],i)
,把2
当作Key
,把·0
当作Value
放入哈希表。当执行到i = 1
时,哈希表中有Key
值为9 - 7 = 2
的桶(上一步放进去的)。因此直接返回该桶的Value
为0
,以及这个i
为1
。所以返回数组return new int[]{ 0 , 1}
,符合预期。
两数相加
题目描述
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
1 | 输入:l1 = [2,4,3], l2 = [5,6,4] |
示例 2:
1 | 输入:l1 = [0], l2 = [0] |
示例 3:
1 | 输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] |
提示:
- 每个链表中的节点数在范围
[1, 100]
内 0 <= Node.val <= 9
- 题目数据保证列表表示的数字不含前导零
题目解法
常规解法
主要学习链表相关操作,对链表的处理上模拟正常计算即可
我们这里举例来方便理解,例如342 + 465 = 807
,我们在计算时先将2
和5
相加得到7
,可以看到我们这里计算时恰好是逆顺计算的,与给出的逆序链表恰好对应,甚至省去了假如位数不同需要对齐的问题,自动末尾对齐了。
1 | /** |
Debug
1 | class Solution |
以上这段代码是错误的,原因是 tail
是一个指针 ,指向当前链表节点,第13行中tail = tail.next = null;
,仅仅会把tail
指针置空,而没其他任何效果。因为在tail = new ListNode(val)
时,默认tail.next = null
,用来默认当前节点是链表的最后一个元素。所以第二次迭代时,仅仅创建了一个没有和任何链表链接的新节点。正确的做法是在创建新节点后,将 tail.next
指向这个新节点,然后再更新 tail
指针指向新的末尾节点。这样,每次迭代时,新创建的节点都会被正确地添加到链表的末尾。 只有创建好新节点,tail.next
才能指向新节点
无重复字符的最长子串
题目描述
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
1 | 输入: s = "abcabcbb" |
示例 2:
1 | 输入: s = "bbbbb" |
示例 3:
1 | 输入: s = "pwwkew" |
提示:
0 <= s.length <= 5 * 104
s
由英文字母、数字、符号和空格组成
题目解法
滑动窗口
1 | class Solution{ |
1.注意第 4 行中的length
是方法,不是属性。需要int n = s.length()
,注意加小括号,这里注意区分两数之和处的int []
类型的nums
的length
是属性,并非方法,无需加括号。
2.还有9行occ.contains(s.charAt(tail))
要去找尾巴,别找错了。
1 | class Solution { |