Leetcode 1-5
1:两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
- 只会存在一个有效答案
思路:通过哈希表存储出现过的数据及其索引。
class Solution { public int[] twoSum(int[] nums, int target) { Map<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:两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
- 每个链表中的节点数在范围
[1, 100]
内 0 <= Node.val <= 9
- 题目数据保证列表表示的数字不含前导零
思路:使用循环依次对每一位进行相加,把进制数携带到下一个循环,同时使用两个对象记录开始的链表和执行中的链表对象。
class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode head = new ListNode(-1), pre = head; int t = 0; while(l1 != null || l2!=null || t!=0){ int sum = t; if(l1 != null){ sum += l1.val; l1 = l1.next; } if(l2 != null){ sum += l2.val; l2 = l2.next; } t = sum/10; pre.next = new ListNode(sum%10); pre = pre.next; } return head.next; } }
3:无重复的字符的最长子串
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
0 <= s.length <= 5 * 104
s
由英文字母、数字、符号和空格组成
思路:循环读取每一个字符,1、使用哈希表记录其所在的下标索引,2、使用变量记录当前记录的 "滑动窗口" 的起始下标,在数据重复时判断其是否在起始下标之后,如果是再重置 "滑动窗口"
class Solution { public int lengthOfLongestSubstring(String s) { HashMap<Character, Integer> map = new HashMap<>(); int maxLength = 0; for (int start = 0,end = 0; end < s.length(); end++) { if(map.containsKey(s.charAt(end)) && map.get(s.charAt(end))>=start){ start = map.get(s.charAt(end))+1; map.remove(s.charAt(end)); }else{ maxLength = Math.max(maxLength, end - start + 1); } map.put(s.charAt(end), end); } return maxLength; } }
4:寻找两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
思路:
(伪)一开始没注意是正序,导致想当然思考先进行排序,再去寻找中位数,因为中位数在总数为奇数时是其中的一个数,偶数时是两个数平均值,所以这里统一计算下标为 (m+n+1)/2 和 (m+n+2)/2 的平均值,使用TreeMap来实现排序以及记录出现的次数,代码如下:
class Solution { public static double findMedianSortedArrays(int[] nums1, int[] nums2) { Map<Double, Integer> hashMap = new TreeMap<>(); int i1 = nums1.length + nums2.length; for (int i = 1; i <= i1; i++) { if(i > nums1.length){ int i2 = i - nums1.length - 1; hashMap.put((double) nums2[i2], hashMap.get((double)nums2[i2])== null?1:hashMap.get((double)nums2[i2])+1); }else{ hashMap.put((double) nums1[i-1], hashMap.get((double)nums1[i-1])==null?1:hashMap.get((double)nums1[i-1])+1); } } if(i1 == 1) return hashMap.keySet().stream().findFirst().get(); return (getNum(hashMap, (i1+1)/2) + getNum(hashMap, (i1+2)/2))/2; } static Double getNum(Map<Double, Integer> hashMap, int i){ int count = 0; for (Double m : hashMap.keySet()) { count += hashMap.get(m); if(count>=i){ return m; } } return (double) 0; } }
结果自然是:
class Solution { public static double findMedianSortedArrays(int[] nums1, int[] nums2) { int i1 = nums1.length + nums2.length; return (getNum(nums1, 0 , nums2, 0, (i1+1)/2) + getNum(nums1, 0 , nums2, 0, (i1+2)/2))/2.0; } static int getNum(int[] nums1,int i1, int[] nums2, int i2, int k){ if(i1 >= nums1.length){ // 为空 return nums2[i2+k-1]; } if(i2 >= nums2.length){ // 为空 return nums1[i1+k-1]; } if(k == 1){ return Math.min(nums1[i1], nums2[i2]); } int avg1 = (i1 + k/2 -1 < nums1.length) ? nums1[i1 + k/2 -1] : Integer.MAX_VALUE; int avg2 = (i2 + k/2 -1 < nums2.length) ? nums2[i2 + k/2 -1] : Integer.MAX_VALUE; if(avg1 < avg2){ return getNum(nums1, i1 + k/2, nums2, i2, k-k/2); }else{ return getNum(nums1, i1, nums2, i2 + k/2, k-k/2); } } }
对于i1、i2 ,表示下标索引, K 表示移动的位数,所以每次涉及 K 的数组取值时都会 -1来保证取到的是正确的下标数据。
5:最长回文子串
s
,找到 s
中最长的回文子串。1、中心扩散:
public static String longestPalindrome(String s) { char[] chars = s.toCharArray(); if(chars.length <= 1){ return s.substring(0,1); } int start = 0, maxLength = 0; for (int i = 0; i < chars.length; i++) { int length = getLength(chars, i, i); int length2 = getLength(chars, i,i+1); int realLength = Math.max(length2, length); if(realLength > maxLength){ start = i - (realLength+1)/2 + 1; maxLength = realLength; } } return s.substring(start, start+maxLength); } static int getLength(char[] chars, int left, int right){ while(left >= 0 && right < chars.length && chars[left] == chars[right]){ left--; right++; } return (right-1)-(left+1)+1; }
这题因为有121和1122两种回文格式,所以在调用 getLength 时两种取值都使用,防止漏掉其中一种
2、动态规划。
class Solution { public String longestPalindrome(String s) { char[] chars = s.toCharArray(); if(chars.length <= 1){ return s.substring(0,1); } int start = 0, maxLength = 1; boolean[][] bp = new boolean[chars.length][chars.length]; for (int i = 0; i < chars.length; i++) { bp[i][i] = true; } for (int j = 0; j < chars.length; j++) { for (int i = 0; i < j; i++) { if(chars[i] != chars[j]){ bp[i][j] = false; }else{ if(j-i < 3){ bp[i][j] = true; }else{ bp[i][j] = bp[i+1][j-1]; } } if(bp[i][j] && (j-i+1)>maxLength){ maxLength = j-i+1; start = i; } } } return s.substring(start, start+maxLength); } }
同样使用两个嵌套循环,同时嵌套添加数组数据,所以时间、空间复杂度都是O(n^2),效率较低。