两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
解题思路:这道题最优的做法时间复杂度是O(n),顺序扫描数组,对每一个元素在map中找能组合给定值的另一半数字,如果找到了直接返回2个数字的下标。如果找不到就把数字放入map,进入下一次循环。
java
class Solution {
public int[] twoSum(int[] nums, int target) {
if (nums == null) {
return null;
}
if (nums.length <= 1) {
return null;
}
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int res = target - nums[i];
if (map.get(res) != null) {
return new int[]{map.get(res), i};
}
map.put(nums[i], i);
}
return null;
}
}
两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位数字。请你将两个数相加,并以相同形式返回一个表示和的链表。
解题思路:为了处理方法统一,可以先建立一个虚拟头节点,这个虚拟头结点的next指向真正的head,这样head不需要单独处理,直接while循环即可。另外判断循环终止的条件不是p.next !=null ,这样最后一位还需要额外计算,循环条件应该是p != null。
sql
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null || l2 == null) {
return null;
}
// 进位的数,要么0要么1
int carry = 0;
ListNode res = new ListNode();
ListNode pre = res;
while(l1 != null ||l2 != null) {
int v1 = l1 == null ? 0 : l1.val;
int v2 = l2 == null ? 0 : l2.val;
// 求和
int sum = v1 + v2 + carry;
// 计算进位
carry = sum / 10;
// 求和排除大于10的情况
sum = sum % 10;
res.next = new ListNode(sum);
res = res.next;
if (l1 != null) {
l1 = l1.next;
}
if (l2 != null) {
l2 = l2.next;
}
}
if (carry == 1) {
// 进位了
res.next = new ListNode(carry);
}
return pre.next;
}
无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
解题思路: 思想是滑动窗口,滑动窗口的右边界不断地右移,只要没有重复的字符,就持续向右扩大窗口边界。一旦出现重复字符,就需要缩小左边界,然后继续移动滑动窗口的右边界。以此类推,每次移动需要计算当前长度,并判断是否需要更新最大长度。
sql
public int lengthOfLongestSubstring(String s) {
int len = s.length();
Set<Character> temp = new HashSet<Character>();
int rk = -1;
int res = 0;
for(int i = 0; i < len; ++i) {
if (i != 0) {
// 从第二个开始,移除前一个
temp.remove(s.charAt(i - 1));
}
while(rk + 1 < len && !temp.contains(s.charAt(rk + 1))) {
// 持续向右移动
temp.add(s.charAt(rk + 1));
++rk;
}
res = Math.max(res, rk - i + 1);
}
return res;
}
求两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数 。算法的时间复杂度应该为 O(log (m+n)) 。
示例 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
解题思路:
- 给出两个有序数组,要求找出这两个数组合并以后的有序数组中的中位数。要求时间复杂度为 O(log (m+n))
- 最容易想到的就是把两个数组合并,然后取出中位数。但是合并数组的复杂度是O(max(m+n)),所以可以考虑使用二分搜索
- 由于要找到最终合并以后数组的中位数,两个数组的总⼤⼩也知道,所以中间这个位置也是知道的。只需要⼆分搜索⼀个数组中切分的位置,另⼀个数组中切分的位置也能得到。为了使得时间复 杂度最⼩,所以⼆分搜索两个数组中⻓度较⼩的那个数组
- 关键的问题是如何切分两个数组。其实就是如何切分数组 1 。先随便⼆分产⽣⼀个 midA,切分的线何时算满⾜了中位数的条件呢?即,线左边的数都⼩于右边的数,即, nums1[midA-1] ≤ nums2[midB] && nums2[midB-1] ≤ nums1[midA] 。如果这些条件都不满 ⾜,切分线就需要调整。如果 nums1[midA] < nums2[midB-1] ,说明 midA 这条线划分出来左 边的数⼩了,切分线应该右移;如果 nums1[midA-1] > nums2[midB] ,说明 midA 这条线划分 出来左边的数⼤了,切分线应该左移。经过多次调整以后,切分线总能找到满⾜条件的解
- 假设现在找到了切分的两条线了, 数组 1 在切分线两边的下标分别是 midA - 1 和 midA 。 数 组 2在切分线两边的下标分别是 midB - 1 和 midB 。最终合并成最终数组,如果数组⻓度是奇 数,那么中位数就是 max(nums1[midA-1], nums2[midB-1]) 。如果数组⻓度是偶数,那么中间 位置的两个数依次是: max(nums1[midA-1], nums2[midB-1]) 和 min(nums1[midA], nums2[midB]) ,那么中位数就是 (max(nums1[midA-1], nums2[midB-1]) + min(nums1[midA], nums2[midB])) / 2 。
sql
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int len = m + n;
int left = -1;
int right = -1;
int aStart = 0;
int bStart = 0;
for(int i = 0; i <= len / 2; i++) {
left = right;
if (aStart < m && (bStart >= n || nums1[aStart] < nums2[bStart])) {
right = nums1[aStart++];
} else {
right = nums2[bStart++];
}
}
if ((len & 1 ) == 0) {
return (left + right) / 2.0;
} else {
return right;
}
}
整数反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
解题思路:只需要注意一点,反转以后的数字要求在 [−2^31, 2^31 − 1]
范围内,超过这个范围的数字都要输出0。
sql
public int reverse(int x) {
int res = 0;
while(x != 0) {
//每次取末尾数字
int tmp = x % 10;
//判断是否 大于 最大32位整数
if (res > 214748364 || (res == 214748364 && tmp > 7)) {
return 0;
}
//判断是否 小于 最小32位整数
if (res < -214748364 || (res == -214748364 && tmp < -8)) {
return 0;
}
res = res * 10 + tmp;
x /= 10;
}
return res;
}