leetcode 6: zigzag conversion
The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N
A P L S I I G
Y I R
And then read line by line: "PAHNAPLSIIGYIR"
Write the code that will take a string and make this conversion given a number of rows:
string convert(string s, int numRows);
Example 1:
Input: s = "PAYPALISHIRING", numRows = 3
Output: "PAHNAPLSIIGYIR"
Example 2:
Input: s = "PAYPALISHIRING", numRows = 4
Output: "PINALSIGYAHRPI"
Explanation:
P I N
A L S I G
Y A H R
P I
Example 3:
Input: s = "A", numRows = 1
Output: "A"
最佳解法:定义一个flag变量,每当遍历到0或者numRows - 1,就修改i的方向
7. Reverse Integer
Given a signed 32-bit integer x, return x with its digits reversed. If reversing x causes the value to go outside the signed 32-bit integer range [-231, 231 - 1], then return 0.
Assume the environment does not allow you to store 64-bit integers (signed or unsigned).
Example 1:
Input: x = 123
Output: 321
Example 2:
Input: x = -123
Output: -321
Example 3:
Input: x = 120
Output: 21
- 做这道题的时候,不需要遍历多次,一个循环可以解决的问题不需要定义多个循环
- 判断是否overflow:
if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && digit > 7)) {
// reversed value is greater than Integer.MAX_VALUE
return 0;
}
if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && digit < -8)) {
// reversed value is less than Integer.MIN_VALUE
return 0;
}
12. Integer to Roman
Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
For example, 2 is written as II in Roman numeral, just two one's added together. 12 is written as XII, which is simply X + II. The number 27 is written as XXVII, which is XX + V + II.
Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:
Ican be placed beforeV(5) andX(10) to make 4 and 9.Xcan be placed beforeL(50) andC(100) to make 40 and 90.Ccan be placed beforeD(500) andM(1000) to make 400 and 900.
Given an integer, convert it to a roman numeral.
Example 1:
Input: num = 3
Output: "III"
Explanation: 3 is represented as 3 ones.
Example 2:
Input: num = 58
Output: "LVIII"
Explanation: L = 50, V = 5, III = 3.
Example 3:
Input: num = 1994
Output: "MCMXCIV"
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
还是写的太过冗余了,参考别人的写法:
public String intToRoman(int num) {
int[] key = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
String[] value = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
StringBuilder res = new StringBuilder();
for(int i = 0; i < key.length; i++) {
while(num >= key[i]) {
num -= key[i];
res.append(value[i]);
}
}
return res.toString();
}
53. Maximum Subarray
Given an integer array nums, find the subarray with the largest sum, and return its sum.
Example 1:
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: The subarray [4,-1,2,1] has the largest sum 6.
Example 2:
Input: nums = [1]
Output: 1
Explanation: The subarray [1] has the largest sum 1.
Example 3:
Input: nums = [5,4,-1,7,8]
Output: 23
Explanation: The subarray [5,4,-1,7,8] has the largest sum 23.
贪心解法:连续和是负数的时候要从头开始
public int maxSubArray(int[] nums) {
int res = Integer.MIN_VALUE;
int count = 0;
for(int i = 0; i < nums.length; i++) {
count += nums[i];
if (count > res) {
res = count;
}
if(count < 0){
count = 0;
}
}
return res;
}
dp解法:dp数组含义:到当前值的largest sum;感觉要把dp子数组再复习一遍
class Solution {
public int maxSubArray(int[] nums) {
int[] dp = new int[nums.length];
dp[0] = nums[0];
int res = dp[0];
for(int i = 1; i < nums.length; i++) {
dp[i] = Math.max(dp[i-1] + nums[i], nums[i]);
res = Math.max(res, dp[i]);
}
return res;
}
}
264. Ugly Number II
An ugly number is a positive integer whose prime factors are limited to 2, 3, and 5.
Given an integer n, return the nth ugly number.
Example 1:
Input: n = 10
Output: 12
Explanation: [1, 2, 3, 4, 5, 6, 8, 9, 10, 12] is the sequence of the first 10 ugly numbers.
Example 2:
Input: n = 1
Output: 1
Explanation: 1 has no prime factors, therefore all of its prime factors are limited to 2, 3, and 5.
解决办法:定义一个factor,{2,3,5} 然后定义一个priorityQueue,每次从pq里pop出一个值再乘以factor。还需要定义一个set避免重复。
下次碰到这种题的时候,可以仔细想一想
备注一下:该题的动态规划解法没有看懂,可以之后看一下
这道题使用了多路归并
class Solution {
public int nthUglyNumber(int n) {
int[] dp = new int[n + 1];
dp[1] = 1;
int p2 = 1;
int p3 = 1;
int p5 = 1;
for(int i = 2; i <= n; i++) {
int a = dp[p2] * 2;
int b = dp[p3] * 3;
int c = dp[p5] * 5;
int next = Math.min(a, Math.min(b, c));
if(next == a) p2++;
if(next == b) p3++;
if(next == c) p5++;
dp[i] = next;
}
return dp[n];
}
}
每次都从 *2 *3和 *5的序列中选择一个最小的
946. Validate Stack Sequences
Given two integer arrays pushed and popped each with distinct values, return true if this could have been the result of a sequence of push and pop operations on an initially empty stack, or false otherwise.
Example 1:
Input: pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
Output: true
Explanation: We might do the following sequence:
push(1), push(2), push(3), push(4),
pop() -> 4,
push(5),
pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
Example 2:
Input: pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
Output: false
Explanation: 1 cannot be popped before 2.
此题解法:模拟栈的过程,新建一个栈,如果碰到和popped数组相同的元素就pop掉。之前写的太复杂了
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
Deque<Integer> dq = new ArrayDeque<>();
int j = 0;
for(int i = 0; i < pushed.length; i++) {
dq.addLast(pushed[i]);
while(!dq.isEmpty() && dq.getLast() == popped[j]) {
dq.removeLast();
j++;
}
}
return dq.isEmpty();
}
}
22. Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
Example 1:
Input: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]
Example 2:
Input: n = 1
Output: ["()"]
本题用dfs可以做出来,不会做是因为之前没接触过此类题型
class Solution {
List<String> res = new ArrayList<>();
public void dfs(String str, int left, int right, int n) {
if(left == n && right == n) {
res.add(str);
return;
}
if(left < right) {
return;
}
if(left < n) { // 注意要有这个判断条件 不然就stack overflow了
dfs(str + "(", left + 1, right, n);
}
if(right < n) {
dfs(str + ")", left, right + 1, n);
}
}
public List<String> generateParenthesis(int n) {
dfs("", 0, 0, n);
return res;
}
}
28. Find the Index of the First Occurrence in a String
Given two strings needle and haystack, return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
Example 1:
Input: haystack = "sadbutsad", needle = "sad"
Output: 0
Explanation: "sad" occurs at index 0 and 6.
The first occurrence is at index 0, so we return 0.
Example 2:
Input: haystack = "leetcode", needle = "leeto"
Output: -1
Explanation: "leeto" did not occur in "leetcode", so we return -1.
这道题除了常规做法可以用kmp做,先码住, 有机会学习一下kmp //todo
29. Divide Two Integers
Given two integers dividend and divisor, divide two integers without using multiplication, division, and mod operator.
The integer division should truncate toward zero, which means losing its fractional part. For example, 8.345 would be truncated to 8, and -2.7335 would be truncated to -2.
Return the quotient after dividing dividend by divisor.
Note: Assume we are dealing with an environment that could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. For this problem, if the quotient is strictly greater than 231 - 1, then return 231 - 1, and if the quotient is strictly less than -231, then return -231.
Example 1:
Input: dividend = 10, divisor = 3
Output: 3
Explanation: 10/3 = 3.33333.. which is truncated to 3.
Example 2:
Input: dividend = 7, divisor = -3
Output: -2
Explanation: 7/-3 = -2.33333.. which is truncated to -2.
这题还是有点难 涉及一堆位运算,还有要注意处理corner case, 还有要注意题目要求,不能转化为long
class Solution {
public int divide(int dividend, int divisor) {
// 考虑被除数为最小值的情况
if (dividend == Integer.MIN_VALUE) {
if (divisor == 1) {
return Integer.MIN_VALUE;
}
if (divisor == -1) {
return Integer.MAX_VALUE;
}
}
// 考虑除数为最小值的情况
if (divisor == Integer.MIN_VALUE) {
return dividend == Integer.MIN_VALUE ? 1 : 0;
}
// 考虑被除数为 0 的情况
if (dividend == 0) {
return 0;
}
boolean negative = (dividend >= 0) == (divisor >= 0) ? false : true;
dividend = Math.abs(dividend);
divisor = Math.abs(divisor);
int res = 0;
while(dividend - divisor >= 0) {
int count = 0;
while(dividend - (divisor << 1 << count) >= 0) { // 相当于每次在前一个数的基础上乘2
count++;
}
res += 1 << count; // (2 ^ count)
dividend -= divisor << count;
}
return negative ? -res : res;
}
}
50. Pow(x, n)
Implement pow(x, n), which calculates x raised to the power n (i.e., xn).
Example 1:
Input: x = 2.00000, n = 10
Output: 1024.00000
Example 2:
Input: x = 2.10000, n = 3
Output: 9.26100
Example 3:
Input: x = 2.00000, n = -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25
第50题可以用这道题相同的思路解决,就是每次都讲上一次的幂乘2,比如说n == 10, x == 2.000 然后我们就先取 2^1, 2^2, 2^4, 2^8, 然后这时候发现 没法再继续乘了,就把之前的count变为0 重新开始计算
class Solution {
public double myPow(double x, int n) {
if (n == Integer.MIN_VALUE) {
if(x == 1) return 1;
if(x == -1) return 1;
else return 0;
}
if (n == Integer.MAX_VALUE) {
if(x == 1) return 1;
if(x == -1) return -1;
else return 0;
}
double res = 1;
boolean negative = n < 0 ? true: false;
n = Math.abs(n);
while(n > 0) {
int count = 0;
double temp = x;
while(n - (1 << count) >= 0) {
res = res * (temp);
temp = temp * temp;
n -= 1 << count;
count++;
}
}
return negative ? 1/res : res;
}
}
31. Next Permutation
A permutation of an array of integers is an arrangement of its members into a sequence or linear order.
- For example, for
arr = [1,2,3], the following are all the permutations ofarr:[1,2,3], [1,3,2], [2, 1, 3], [2, 3, 1], [3,1,2], [3,2,1].
The next permutation of an array of integers is the next lexicographically greater permutation of its integer. More formally, if all the permutations of the array are sorted in one container according to their lexicographical order, then the next permutation of that array is the permutation that follows it in the sorted container. If such arrangement is not possible, the array must be rearranged as the lowest possible order (i.e., sorted in ascending order).
- For example, the next permutation of
arr = [1,2,3]is[1,3,2]. - Similarly, the next permutation of
arr = [2,3,1]is[3,1,2]. - While the next permutation of
arr = [3,2,1]is[1,2,3]because[3,2,1]does not have a lexicographical larger rearrangement.
Given an array of integers nums, find the next permutation of nums.
The replacement must be in place and use only constant extra memory.
Example 1:
Input: nums = [1,2,3]
Output: [1,3,2]
Example 2:
Input: nums = [3,2,1]
Output: [1,2,3]
Example 3:
Input: nums = [1,1,5]
Output: [1,5,1]
这道题就是找最后一个降序排列,前面的升序排列中的前一个值,下面代码中j就是其index
如果没找到j 说明整个数组都是升序排列的,那么就reverse一下数组就ok了
如果找到了 再从后向前遍历,如果然后找第一个比j大的数,交换这两个数,再将j+1后面的值从小到大排序即可
class Solution {
public void nextPermutation(int[] nums) {
if(nums.length == 1) return;
int j = -1;
for(int i = 1; i < nums.length; i++) {
if(nums[i - 1] < nums[i]) {
j = i - 1;
}
}
if(j == -1) {
// Reverse the sorted array
for (int i = 0; i < nums.length / 2; i++) {
int temp = nums[i];
nums[i] = nums[nums.length - 1 - i];
nums[nums.length - 1 - i] = temp;
}
return;
}
for(int i = nums.length - 1; i >= j+1 ; i--) {
if(nums[i] > nums[j]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
break;
}
}
Arrays.sort(nums, j+1, nums.length);
}
}
33 和 81题一起写,都是关于rotated sorted array的二分查找
33是不含重复元素
81是含重复元素
33. Search in Rotated Sorted Array
There is an integer array nums sorted in ascending order (with distinct values).
Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2].
Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums , or -1 if it is not in nums.
You must write an algorithm with O(log n) runtime complexity.
Example 1:
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Example 2:
Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
Example 3:
Input: nums = [1], target = 0
Output: -1
精髓:
将数组一分为二,其中一定有一个是有序的,另一个可能是有序,也能是部分有序。
此时有序部分用二分法查找。无序部分再一分为二,其中一个一定有序,另一个可能有序,可能无序。就这样循环.
但是还是要注意一下边界问题:
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <=right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
} else if(nums[left] <= nums[mid]) {
// 这里要注意一下,因为二分法是向下取整,所以要写nums[left] <= nums[mid]
if(nums[mid] < target && target <= nums[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
} else {
if(nums[left] <= target && target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return -1;
}
}
81. Search in Rotated Sorted Array II
There is an integer array nums sorted in non-decreasing order (not necessarily with distinct values).
Before being passed to your function, nums is rotated at an unknown pivot index k (0 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,4,4,5,6,6,7] might be rotated at pivot index 5 and become [4,5,6,6,7,0,1,2,4,4].
Given the array nums after the rotation and an integer target, return true if target is in nums , or false if it is not in nums .
You must decrease the overall operation steps as much as possible.
Example 1:
Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true
Example 2:
Input: nums = [2,5,6,0,0,1,2], target = 3
Output: false
81题需要考虑一个特殊情况,就是可能nums[mid] == nums[left] == nums[right]。这样就无法判断target是在左区间还是右区间了。这个时候就直接做left++ 和 right--的操作即可
class Solution {
public boolean search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right) {
int mid = (left + right) / 2;
if(nums[mid] == target) {
return true;
}
if(nums[left] == nums[mid] && nums[mid] == nums[right]) {
left++;
right--;
} else if(nums[left] <= nums[mid]) {
if(nums[left] <= target && target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if(nums[mid] < target && target <= nums[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return false;
}
}
另一个二分法应用: sqrt(x) 69. Sqrt(x)
Given a non-negative integer x, return the square root of x rounded down to the nearest integer. The returned integer should be non-negative as well.
You must not use any built-in exponent function or operator.
- For example, do not use
pow(x, 0.5)in c++ orx ** 0.5in python.
Example 1:
Input: x = 4
Output: 2
Explanation: The square root of 4 is 2, so we return 2.
Example 2:
Input: x = 8
Output: 2
Explanation: The square root of 8 is 2.82842..., and since we round it down to the nearest integer, 2 is returned.
这道题面试常考,典型的二分法:
class Solution {
public int mySqrt(int x) {
int l = 0;
int r = x;
while(l <= r) {
int mid = l + ((r - l) / 2);
if((long) mid * mid <= x) {
l = mid + 1;
} else {
r = mid -1;
}
}
return l-1;
}
}
l-1是因为我们找的是左边界,l一直取的是mid + 1,所以最终结果就是l-1
另外一道题: 35. Search Insert Position
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You must write an algorithm with O(log n) runtime complexity.
Example 1:
Input: nums = [1,3,5,6], target = 5
Output: 2
Example 2:
Input: nums = [1,3,5,6], target = 2
Output: 1
Example 3:
Input: nums = [1,3,5,6], target = 7
Output: 4
这道题可以直接返回l的原因,是因为题里问的就是找下一个插入的位置,所以直接返回l即可
34题 二分查找左边界和右边界
34. Find First and Last Position of Element in Sorted Array
Given an array of integers nums sorted in non-decreasing order, find the starting and ending position of a given target value.
If target is not found in the array, return [-1, -1].
You must write an algorithm with O(log n) runtime complexity.
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
Example 3:
Input: nums = [], target = 0
Output: [-1,-1]
左边界和右边界获取:分别是left - 1 获取右边界,right + 1 获取左边界。前两道题用left获取左边界是因为没有重复元素:
public int getRightborder(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right) {
int mid = (left + right) / 2;
if(nums[mid] <= target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left - 1;
}
public int getLeftborder(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int leftBorder = -1;
while(left <= right) {
int mid = (left + right) / 2;
if(nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return right + 1;
}
97. Interleaving String
Given strings s1, s2, and s3, find whether s3 is formed by an interleaving of s1 and s2.
An interleaving of two strings s and t is a configuration where s and t are divided into n and m
substrings
respectively, such that:
s = s1 + s2 + ... + snt = t1 + t2 + ... + tm|n - m| <= 1- The interleaving is
s1 + t1 + s2 + t2 + s3 + t3 + ...ort1 + s1 + t2 + s2 + t3 + s3 + ...
Note: a + b is the concatenation of strings a and b.
Example 1:
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
Output: true
Explanation: One way to obtain s3 is:
Split s1 into s1 = "aa" + "bc" + "c", and s2 into s2 = "dbbc" + "a".
Interleaving the two splits, we get "aa" + "dbbc" + "bc" + "a" + "c" = "aadbbcbcac".
Since s3 can be obtained by interleaving s1 and s2, we return true.
Example 2:
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
Output: false
Explanation: Notice how it is impossible to interleave s2 with any other string to obtain s3.
Example 3:
Input: s1 = "", s2 = "", s3 = ""
Output: true
- 这道题最开始想用双指针直接做,但是发现不行,因为如果s1和s2中的两个char相同,可以取s1或s2,但是双指针会直接取一个,假设有一个字符串某处p只能取s2但是双指针算法取了s1就会导致结果错误
- 之后就想双指针 + dfs能不能做出来,做出来但是超时了
- 最后就剩动态规划了,动态规划的一个难点就是确定是一维还是二维,如果用二维,如何确定哪个指针指向s3。dp数组的定义是到dp[i][j]能不能组成s3的前i+j-1的字符串。
至于为什么dp的长度要设置成len1+1和len2+1,是因为这样方便计算p = i + j - 1;不然如果设置成len1和len2,这样p = i+j+1,但是初始化会比较麻烦,如果遇到i = 0 j = 0,此时p也等于0,但是p!=i+j+1
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
if(s1.length() + s2.length() != s3.length()) {
return false;
}
int len1 = s1.length();
int len2 = s2.length();
boolean[][] dp = new boolean[len1 + 1][len2 + 1];
dp[0][0] = true;
for(int i = 0; i <= len1; i++) {
for(int j = 0; j <= len2; j++) {
int p = i + j - 1;
if(i >= 1 && dp[i-1][j] && s1.charAt(i-1) == s3.charAt(p)) {
dp[i][j] = true;
}
if(j >= 1 && dp[i][j-1] && s2.charAt(j-1) == s3.charAt(p)) {
dp[i][j] = true;
}
}
}
return dp[len1][len2];
}
}
329. Longest Increasing Path in a Matrix
Given an m x n integers matrix, return the length of the longest increasing path in matrix.
From each cell, you can either move in four directions: left, right, up, or down. You may not move diagonally or move outside the boundary (i.e., wrap-around is not allowed).
Example 1:
Input: matrix = [[9,9,4],[6,6,8],[2,1,1]]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9].
Example 2:
Input: matrix = [[3,4,5],[3,2,6],[2,2,1]]
Output: 4
Explanation: The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed.
Example 3:
Input: matrix = [[1]]
Output: 1
这道题用了dfs + 记忆化存储 最开始是用plain dfs写的,会导致超时,所以需要用记忆化存储,记录每个点的最长路径。然后这样下次再访问这个点的时候可以直接遍历
class Solution {
int[][] dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}};
public int dfs(int i, int j, int[][] matrix, int[][] memo) {
if(memo[i][j] != 0) {
return memo[i][j];
}
memo[i][j]++;
int m = matrix.length;
int n = matrix[0].length;
for(int[] dir: dirs) {
int r = i + dir[0];
int c = j + dir[1];
if(r < 0 || r >= m || c < 0 || c >= n) {
continue;
}
if(matrix[r][c] > matrix[i][j]) {
memo[i][j] = Math.max(memo[i][j], dfs(r, c, matrix, memo) + 1);
}
}
return memo[i][j];
}
public int longestIncreasingPath(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
int[][] memo = new int[m][n];
int res = 0;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
res = Math.max(res, dfs(i, j, matrix, memo));
}
}
return res;
}
}
187. Repeated DNA Sequences
Medium
The DNA sequence is composed of a series of nucleotides abbreviated as 'A', 'C', 'G', and 'T'.
- For example,
"ACGAATTCCG"is a DNA sequence.
When studying DNA, it is useful to identify repeated sequences within the DNA.
Given a string s that represents a DNA sequence, return all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule. You may return the answer in any order.
Example 1:
Input: s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT"
Output: ["AAAAACCCCC","CCCCCAAAAA"]
Example 2:
Input: s = "AAAAAAAAAAAAA"
Output: ["AAAAAAAAAA"]
欢迎收看我是傻逼系列 之前想这怎么比啊,用hashset一存就好了呀
真看懂了这道题目的话,会发现其实真的不难,乍一看没头绪的盆友不妨改一个简单题的情景来想像一下:如果题目的要求变为判断“单字符”是否在串中重复,那你总会写了吧?
思路无非就是先遍历整个字符串一次,然后把记录放在哈希表中,然后看看哪个记录出现多次,那就返回哪个。
而这道题不同于这个简单的情景在于,我们要判断的是有着一定序列的字符组合,为了解决组合的问题,我们仅需按10个字符为一个单位来遍历字符串就可以解决了,再同样使用哈希表来记录
class Solution {
public List<String> findRepeatedDnaSequences(String s) {
List<String> res = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();
for(int i = 0; i <= s.length() - 10; i++) {
String substr = s.substring(i, i+10);
map.put(substr, map.getOrDefault(substr, 0) + 1);
if(map.get(substr) == 2) {
res.add(substr);
}
}
return res;
}
}
128. Longest Consecutive Sequence
Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence.
You must write an algorithm that runs in O(n) time.
Example 1:
Input: nums = [100,4,200,1,3,2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
Example 2:
Input: nums = [0,3,7,2,5,8,4,6,0,1]
Output: 9
其实只需要关心左右边界,比如说边界是[2, 6], 不需要关心边界内的数 比如3,4,因为这些数肯定出现过。之前没写出来就是没考虑清楚,只需要考虑边界。
- 用哈希表存储每个端点值对应连续区间的长度
- 若数已在哈希表中:跳过不做处理
- 若是新数加入:
- 取出其左右相邻数已有的连续区间长度 left 和 right
- 计算当前数的区间长度为:cur_length = left + right + 1
- 根据 cur_length 更新最大长度 max_length 的值
- 更新区间两端点的长度值
class Solution {
public int longestConsecutive(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
int max_length = 0;
for(int i = 0; i < nums.length; i++) {
if(!map.containsKey(nums[i])) {
int left = map.getOrDefault(nums[i] - 1, 0);
int right = map.getOrDefault(nums[i] + 1, 0);
int curr_length = left + right + 1;
max_length = Math.max(max_length, curr_length);
map.put(nums[i], 0); //这一步是把这个数放进map,值是多少无所谓
map.put(nums[i] - left, curr_length);
map.put(nums[i] + right, curr_length);
}
}
return max_length;
}
}
162. Find Peak Element
A peak element is an element that is strictly greater than its neighbors.
Given a 0-indexed integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.
You may imagine that nums[-1] = nums[n] = -∞. In other words, an element is always considered to be strictly greater than a neighbor that is outside the array.
You must write an algorithm that runs in O(log n) time.
Example 1:
Input: nums = [1,2,3,1]
Output: 2
Explanation: 3 is a peak element and your function should return the index number 2.
Example 2:
Input: nums = [1,2,1,3,5,6,4]
Output: 5
Explanation: Your function can return either index number 1 where the peak element is 2, or index number 5 where the peak element is 6.
我自己的解法非常直观,但是标准答案很简洁 很不容易理解
当前比右边小,那么肯定在右边会有峰顶,最差情况走到头,也是一个峰顶; 如果当前比左边小,那么肯定在左边会有峰顶,最差情况一路走到头,也是一个峰顶。
找右边界 + 1肯定是峰值
class Solution {
public int findPeakElement(int[] nums) {
int left = 0;
int right = nums.length - 2;
while(left <= right) {
int mid = left + (right - left) / 2;
if(nums[mid] > nums[mid + 1]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return right + 1;
}
}
167. Two Sum II - Input Array Is Sorted
Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 < numbers.length.
Return the indices of the two numbers, index1 and index2 , added by one as an integer array [index1, index2] of length 2.
The tests are generated such that there is exactly one solution. You may not use the same element twice.
Your solution must use only constant extra space.
Example 1:
Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore, index1 = 1, index2 = 2. We return [1, 2].
Example 2:
Input: numbers = [2,3,4], target = 6
Output: [1,3]
Explanation: The sum of 2 and 4 is 6. Therefore index1 = 1, index2 = 3. We return [1, 3].
Example 3:
Input: numbers = [-1,0], target = -1
Output: [1,2]
Explanation: The sum of -1 and 0 is -1. Therefore index1 = 1, index2 = 2. We return [1, 2].
这种单调递增的array需要想到是双指针 第一次只想到双循环 + 去重 是不够的
172. Factorial Trailing Zeroes
Given an integer n, return the number of trailing zeroes in n!.
Note that n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1.
Example 1:
Input: n = 3
Output: 0
Explanation: 3! = 6, no trailing zero.
Example 2:
Input: n = 5
Output: 1
Explanation: 5! = 120, one trailing zero.
Example 3:
Input: n = 0
Output: 0
这道题的关键解法是数5的个数
class Solution {
public int trailingZeroes(int n) {
int count = 0;
for(int i = 5; i <= n; i+=5) {
int x = i;
while(x % 5 == 0) {
x = x / 5;
count++;
}
}
return count;
}
}
705/706 新建hash set和hash map 新建哈希表的题,如果constraint太大,可以用mod去map,然后把值都存在linkedlist里,就是每一个array都是linkedlist。这个是哈希表的原理,一定要熟记 然后如果哈希查询变慢了,优化方法是直接double array size,然后把之前的array copy到 double的array上去 时间复杂度:O(n/b) 其中 n 为哈希表中的元素数量,b 为链表的数量。假设哈希值是均匀分布的,则每个链表大概长度为n/b 空间复杂度:O(n+b)
class MyHashSet {
List[] arr;
public MyHashSet() {
arr = new LinkedList[1000];
}
public void add(int key) {
int index = hash(key);
if(arr[index] == null) {
List<Integer> list = new LinkedList<>();
list.add(key);
arr[index] = list;
} else {
List<Integer> list = arr[index];
for(int item: list) {
if(item == key) {
return;
}
}
list.add(key);
}
}
public void remove(int key) {
int index = hash(key);
if(arr[index] == null) return;
List<Integer> list = arr[index];
for(int i = 0; i < list.size(); i++) {
if(list.get(i) == key) {
list.remove(i);
return;
}
}
}
public boolean contains(int key) {
int index = hash(key);
if(arr[index] == null) return false;
List<Integer> list = arr[index];
for(int item: list) {
if(item == key) {
return true;
}
}
return false;
}
public int hash(int key) {
return key % 1000;
}
}
179. Largest Number
Given a list of non-negative integers nums, arrange them such that they form the largest number and return it.
Since the result may be very large, so you need to return a string instead of an integer.
Example 1:
Input: nums = [10,2]
Output: "210"
Example 2:
Input: nums = [3,30,34,5,9]
Output: "9534330"
自定义排序,判断半天才想到可以直接比较s1 + s2 和 s2 + s1