1.两数之和(1 - 易)
题目描述:给定一个整数数组 nums
和一个整数目标值 target
,在该数组中找出 和为目标值 的那 两个 整数,返回它们的数组下标。
示例 :
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
思路:本题可以多解法,但是核心考察点为哈希表,即建立值与索引的映射值,遍历数组获取结果。
代码实现:
public int[] twoSum(int[] nums, int target) { HashMap<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { if (map.containsKey(target - nums[i])) { return new int[] {map.get(target - nums[i]), i}; } map.put(nums[i], i); } return null; }
2.两数之和II(167 - 易)
题目描述:给定数组升序,下标从1开始。
示例 :
输入:numbers = [2,3,4], target = 6 输出:[1,3]
思路:本题可以使用哈希表,但是数组严格升序。利用这一性质,可以定义双指针,遍历数组比较大小。
注意:不能使用二分查找,因为最终结果可能分别分布在两个区间。
代码实现:
public int[] twoSum(int[] numbers, int target) { int left = 0, right = numbers.length - 1; while (left < right) { int sum = numbers[left] + numbers[right]; if (sum > target) { right--; } else if (sum < target) { left++; } else { break; } } return new int[] {left + 1, right + 1}; }
3.两数之和IV(653 - 易)
题目描述:判断二叉搜索树是否有两个元素的和为目标值。
示例 :
输入: 5 / \ 3 6 / \ \ 2 4 7 Target = 9 输出: True
思路:
法1:直接递归遍历二叉搜索树,利用set存储节点,判断是否出现k - root.val
。
法2:利用bst中序升序,双指针求解,如167题。
代码实现:直接遍历
private Set<Integer> set = new HashSet<>(); public boolean findTarget(TreeNode root, int k) { if (root == null) return false; if (set.contains(k - root.val)) return true; set.add(root.val); return findTarget(root.left, k) || findTarget(root.right, k); }
4.两整数之和(371 - 中)
题目描述:不使用运算符 +
和 -
,计算两整数 a
、b
之和。
示例 :
输入: a = 1, b = 2 输出: 3
思路:位运算模拟两数相加(可自行举例):可以递归或者迭代实现。
- 按位计算二进制相加(不算进位),相当于二进制按位异或操作。
- 计算进位值,相当于两个数按位与,再进行左移
- 重复上述操作直到进位值b为0,得到累加和a。
代码实现:
public int getSum(int a, int b) { while (b != 0) { int tmp = a ^ b; b = (a & b) << 1; a = tmp; } return a; // 递归实现 return b == 0 ? a : getSum(a ^ b, (a & b) << 1); }
5.两数相加(2 - 中)
题目描述:按照链表逆序形式存储的两个数进行加和,以相同的形式返回结果。数字不含前导0。
示例 :
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807.
思路:使用迭代模拟两数相加的过程:
- 先计算两节点值加和
sumVal
,注意:加上上一轮的进位值 - 记录进位值
carry
- 建立结果链表并连接
- 更新索引值,包括结果链表、
l1和l2
代码实现:
public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode dummyHead = new ListNode(0); ListNode cur = dummyHead; int carry = 0; while (l1 != null || l2 != null || carry != 0) { int sum = carry; sum += l1 == null ? 0 : l1.val; sum += l2 == null ? 0 : l2.val; carry = sum / 10; ListNode sumNode = new ListNode(sum % 10); cur.next = sumNode; cur = sumNode; if (l1 != null) l1 = l1.next; if (l2 != null) l2 = l2.next; } return dummyHead.next; }
6.两数相加II(445 - 中)
题目描述:给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。要求:不修改链表。
示例 :
输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 8 -> 0 -> 7
思路:本题关键使用两个栈实现逆序取出链表的元素进行相加,剩下的解题思路与上题类似。
注意:我们最后返回的结果也是按照正序进行连接的,所以链表要进行倒序连接。
代码实现:
public ListNode addTwoNumbers(ListNode l1, ListNode l2) { Stack<Integer> stack1 = new Stack<>(); Stack<Integer> stack2 = new Stack<>(); while (l1 != null) { stack1.push(l1.val); l1 = l1.next; } while (l2 != null) { stack2.push(l2.val); l2 = l2.next; } int carry = 0; ListNode head = null; while (!stack1.isEmpty() || !stack2.isEmpty() || carry > 0) { int sum = carry; sum += (stack1.isEmpty()) ? 0 : stack1.pop(); sum += (stack2.isEmpty()) ? 0 : stack2.pop(); ListNode node = new ListNode(sum % 10); node.next = head; head = node; carry = sum / 10; } return head; }
7.两数相加II(445 - 中)
题目描述:给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。要求:不修改链表。
示例 :
输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 8 -> 0 -> 7
思路:本题关键使用两个栈实现逆序取出链表的元素进行相加,剩下的解题思路与上题类似。
注意:我们最后返回的结果也是按照正序进行连接的,所以链表要进行倒序连接。
代码实现:
public ListNode addTwoNumbers(ListNode l1, ListNode l2) { Stack<Integer> stack1 = new Stack<>(); Stack<Integer> stack2 = new Stack<>(); while (l1 != null) { stack1.push(l1.val); l1 = l1.next; } while (l2 != null) { stack2.push(l2.val); l2 = l2.next; } int carry = 0; ListNode head = null; while (!stack1.isEmpty() || !stack2.isEmpty() || carry > 0) { int sum = carry; sum += (stack1.isEmpty()) ? 0 : stack1.pop(); sum += (stack2.isEmpty()) ? 0 : stack2.pop(); ListNode node = new ListNode(sum % 10); node.next = head; head = node; carry = sum / 10; } return head; }