赞
踩
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入 | 输出 |
---|---|
nums = [2,7,11,15], target = 9 | [0,1] |
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入 | 输出 |
---|---|
nums = [3,2,4], target = 6 | [1,2] |
示例 3:
输入 | 输出 |
---|---|
nums = [3,3], target = 6 | [0,1] |
// 两数之和:哈希表 class Solution { public int[] twoSum(int[] nums, int target) { Map<Integer,Integer>hashtable = new HashMap<Integer,Integer>();//建立哈希表 for(int i=0;i<nums.length;++i){ //遍历数组 if(hashtable.containsKey(target-nums[i])){ //如果哈希表中存在目标值减去当前值 return new int[]{ hashtable.get(target-nums[i]),i};//则返回另一个数的索引以及当前数的索引 } hashtable.put(nums[i],i);//如果哈希表中不存在,则将当前数以及下标分别存到哈希表的Key和Value上 } return new int[0];//如果遍历完数组,还是没找到结果,则返回空数组 } }
时间复杂度为O(n),n为数组的长度,遍历数组耗费O(n)的时间
空间复杂度为O(n),哈希表最大存储空间
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入 | 输出 |
---|---|
l1 = [2,4,3], l2 = [5,6,4] | [7,0,8] |
解释:342 + 465 = 807.
示例 2:
输入 | 输出 |
---|---|
l1 = [0], l2 = [0] | [0] |
示例 3:
输入 | 输出 |
---|---|
l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] | [8,9,9,9,0,0,0,1] |
// 两数相加:链表 class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode pre = new ListNode(0);//建立新链表 ListNode cur = pre;//当前节点 int carry=0;//进位值 while(l1 != null || l2 != null){ //判断是否遍历完两个链表 int x = l1 != null ? l1.val : 0;//l1未遍历完,则取它的值 int y = l2 != null ? l2.val : 0;//同理 int sum = x + y + carry;//两个链表的节点值加进位值 carry = sum / 10;//新的进位值 sum %= 10;//新链表的节点值 cur.next = new ListNode(sum);//将节点值插入新链表 cur = cur.next;//指针指向下一位置 if(l1 != null)//判断是否遍历完l1 l1 = l1.next; if(l2 != null)//同理 l2 = l2.next; } if(carry != 0){ //如果遍历完了两个链表,还存在进位,则将进位值加入新链表 cur.next = new ListNode(carry); } return pre.next; } }
时间复杂度为O(max(m,n)),m,n为两个链表的长度
空间复杂度为O(1)
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入 | 输出 |
---|---|
s = “abcabcbb” | 3 |
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入 | 输出 |
---|---|
s = “bbbbb” | 1 |
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入 | 输出 |
---|---|
s = “pwwkew” | 3 |
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
示例 4:
输入 | 输出 |
---|---|
s = “” | 0 |
// 无重复字符的最长子串:滑动窗口 class Solution { public int lengthOfLongestSubstring(String s) { Set<Character> occ = new HashSet<Character>();//建立哈希集合 int n = s.length(); int rk = -1, ans = 0;// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动 for (int i = 0; i < n; ++i) { if (i != 0) { occ.remove(s.charAt(i - 1));// 左指针向右移动一格,移除一个字符 } while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) { //哈希集合中不存在当前字符 occ.add(s.charAt(rk + 1));// 不断地移动右指针 ++rk; } ans = Math.max(ans, rk - i + 1);//如果遇到重复字符,则先退出去比较长度 } return ans; } }
时间复杂度为O(n),n为字符串的长度
空间复杂度为O(∣Σ∣),Σ为字符集的大小,哈希集合存储大小
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
示例 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
示例 3:
输入 | 输出 |
---|---|
nums1 = [0,0], nums2 = [0,0] | 0.00000 |
示例 4:
输入 | 输出 |
---|---|
nums1 = [], nums2 = [1] | 1.00000 |
示例 5:
输入 | 输出 |
---|---|
nums1 = [2], nums2 = [] | 2.00000 |
// 寻找两个正序数组的中位数:二分查找 class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { //寻找中位数 int length1 = nums1.length, length2 = nums2.length; int totalLength = length1 + length2; if (totalLength % 2 == 1) { //两个数组相加为奇数 int midIndex = totalLength / 2;//两个数组元素个数的一半 double median = getKthElement(nums1, nums2, midIndex + 1); return median; } else { //为偶数时 int midIndex1 = totalLength / 2 - 1, midIndex2 = totalLength / 2; double median = (getKthElement(nums1, nums2, midIndex1 + 1) + getKthElement(nums1, nums2, midIndex2 + 1)) / 2.0;//求两个相邻元素和的一半 return median; } } public int getKthElement(int[] nums1, int[] nums2, int k) { //得到第k个元素 int length1 = nums1.length, length2 = nums2.length; int index1 = 0, index2 = 0; int kthElement = 0; while (true) { if (index1 == length1) { //数组1为空 return nums2[index2 + k - 1]; } if (index2 == length2) { //数组2为空 return nums1[index1 + k - 1]; } if (k == 1) { //中间数为1,则返回最小的数组中的值 return Math.min(nums1[index1], nums2[index2]); } int half = k / 2; int newIndex1 = Math.min(index1 + half, length1) - 1; int newIndex2 = Math.min(index2 + half, length2) - 1;//找到各自矩阵的最小值 int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2]; if (pivot1 <= pivot2) { //比较两个数组当前值(从最小值开始比较) k -= (newIndex1 - index1 + 1);//如果数组二大。则k减去索引 index1 = newIndex1 + 1;//变更数组1为下一个值 } else { //同理,直到k为0 k -= (newIndex2 - index2 + 1); index2 = newIndex2 + 1; } } } }
时间复杂度为O(log(m+n)),m和n为数组nums1和nums2的长度
空间复杂度为O(1)
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入 | 输出 |
---|---|
s = “babad” | “bab” |
示例 2:
输入 | 输出 |
---|---|
s = “cbbd” | “bb” |
示例 3:
输入 | 输出 |
---|---|
s = “a” | “a” |
示例 4:
输入 | 输出 |
---|---|
s = “ac” | “a” |
// 最长回文子串:双指针 class Solution { public String longestPalindrome(String s) { if (s == null || s.length() < 1) { return ""; } int start = 0, end = 0; for (int i = 0; i < s.length(); i++) { int len1 = expandAroundCenter(s, i, i);//中间有单个字符的回文串 int len2 = expandAroundCenter(s, i, i + 1);//中间无单个字符的回文串 int len = Math.max(len1, len2);//找到最大长度 if (len > end - start) { //如果最大长度比字符串首尾位置差还大 start = i - (len - 1) / 2;//则起点为首位 end = i + len / 2;//终点位末位 } } return s.substring(start, end + 1);//将从起点到结尾的字符输出 } public int expandAroundCenter(String s, int left, int right) { //中心扩展 while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) { //如果左右指针在字符串内且左右指针所指的值一样 --left; ++right;//则左指针左移,右指针右移 } return right - left - 1;//直到左右出范围或者左右指针所指字符不等,则返回左右指针之间的距离 } }
时间复杂度为O( n 2 n^2 n2),n为字符串的长度
空间复杂度为O(1)
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
’ * ’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
示例 1:
输入 | 输出 |
---|---|
s = “aa” p = “a” | false |
解释:“a” 无法匹配 “aa” 整个字符串。
示例 2:
输入 | 输出 |
---|---|
输入:s = “ab” p = “.*” | true |
示例 3:
输入 | 输出 |
---|---|
s = “aa” p = “a*” | true |
解释:因为 ‘*’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 4:
输入 | 输出 |
---|---|
输入:s = “aab” p = “cab” | true |
解释:因为 ‘*’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。
示例 5:
输入 | 输出 |
---|---|
s = “mississippi” p = “misisp*.” | false |
// 正则表达式匹配:动态规划 class Solution { public boolean isMatch(String s, String p) { int m = s.length(); int n = p.length(); boolean[][] f = new boolean[m + 1][n + 1]; f[0][0] = true; for (int i = 0; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (p.charAt(j - 1) == '*') { //如果p中第j-1个字符是*,则可以匹配多次 f[i][j] = f[i][j - 2];//对p中第j-1个字符匹配多次,匹配0次的情况 if (matches(s, p, i, j - 1)) { //判断匹配 f[i][j] = f[i][j] || f[i - 1][j];//如果符合,则字符串s中前i个字符和字符串p中前j个字符是否匹配取决于前一个i和当前的i是否匹配 } } else { if (matches(s, p, i, j)) { //如果p的第j个字符是一个小写字母 f[i][j] = f[i - 1][j - 1];//则是否匹配取决于i-1和j-1 } } } } return f[m][n]; } public boolean matches(String s, String p, int i, int j) { //匹配判断 if (i == 0) { return false; } if (p.charAt(j - 1) == '.') { //出现‘.’代表匹配 return true; } return s.charAt(i - 1) == p.charAt(j - 1);//字符是否匹配 } }
时间复杂度为O(mn),m和n分别为字符串s和p的长度
空间复杂度为O(mn)
给你 n 个非负整数 a 1 , a 2 , . . . , a n , a_1,a_2,...,a_n, a1,a2,...,an,每个数代表坐标中的一个点 (i, a i a_i ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, a i a_i ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
示例 1:
输入 | 输出 |
---|---|
[1,8,6,2,5,4,8,3,7] | 49 |
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入 | 输出 |
---|---|
height = [1,1] | 1 |
示例 3:
输入 | 输出 |
---|---|
height = [4,3,2,1,4] | 16 |
示例 4:
输入 | 输出 |
---|---|
height = [1,2,1] | 2 |
// 盛最多水的容器:双指针 public class Solution { public int maxArea(int[] height) { int l = 0, r = height.length - 1;//定义双指针,指向首尾 int ans = 0; while (l < r) { int area = Math.min(height[l], height[r]) * (r - l);//比较高度,找出左右边界最低的高度,然后乘上左右边界之间的距离 ans = Math.max(ans, area); if (height[l] <= height[r]) { //比较左右边界高度 ++l;//左边低,左指针右移 } else { --r;//右边低,右指针左移 } } return ans; } }
时间复杂度为O(n),n为数组的长度
空间复杂度为O(1)
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入 | 输出 |
---|---|
nums = [-1,0,1,2,-1,-4] | [[-1,-1,2],[-1,0,1]] |
示例 2:
输入 | 输出 |
---|---|
nums = [] | [] |
示例 3:
输入 | 输出 |
---|---|
nums = [0] | [] |
// 三数之和:排序 + 双指针 class Solution { public List<List<Integer>> threeSum(int[] nums) { int n = nums.length; Arrays.sort(nums);//排序 List<List<Integer>> ans = new ArrayList<List<Integer>>(); for (int first = 0; first < n; ++first) { //第一个数 if (first > 0 && nums[first] == nums[first - 1]) { //当first大于0且相邻两个数相等时,跳过 continue; } int third = n - 1;//第三个数 int target = -nums[first];//目标值 for (int second = first + 1; second < n; ++second) { //第二个数在第一个数之后 if (second > first + 1 && nums[second] == nums[second - 1]) { //如果第二个数在第一个数后一个位置以后,且相邻两个数相等时,跳过 continue; } while (second < third && nums[second] + nums[third] > target) { //如果第二个数加第三个数大于目标值,则第三个数右移 --third; } if (second == third) { //如果第二个数等于第三个数,则终止本层循环 break; } if (nums[second] + nums[third] == target) { //如果第二个数和第三个数相加等于目标值,则输出结果 List<Integer> list = new ArrayList<Integer>(); list.add(nums[first]); list.add(nums[second]); list.add(nums[third]); ans.add(list); } } } return ans; } }
时间复杂度为O( N 2 N^2 N2),n为数组的长度
空间复杂度为O( log N
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。