给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
解题思路:这道题最优的做法时间复杂度是O(n),顺序扫描数组,对每一个元素在map中找能组合给定值的另一半数字,如果找到了直接返回2个数字的下标。如果找不到就把数字放入map,进入下一次循环。
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。
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" 是一个子序列,不是子串。
解题思路: 思想是滑动窗口,滑动窗口的右边界不断地右移,只要没有重复的字符,就持续向右扩大窗口边界。一旦出现重复字符,就需要缩小左边界,然后继续移动滑动窗口的右边界。以此类推,每次移动需要计算当前长度,并判断是否需要更新最大长度。
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
解题思路:
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。
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;
}