目录
前言:
纯作者做题的时候手敲的。有的题目代码,我写的可能是和常见的题解一样,有的是作者自已认为比较好理解的方法。由于是手敲,有一些是我写完copy过来的,有一些是我写完copy到做题网站的,所以会有各别题可能会有问题,如果发现请及时联系我修改,谢谢!
11.滑动窗口的最大值
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1 输出:[1]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int[] res = new int[nums.length-k+1];
Deque<Integer> q = new LinkedList();
for(int i=0;i<nums.length;i++){
if(!q.isEmpty()&&i-k+1>q.getFirst()) q.pollFirst();
while(!q.isEmpty()&&nums[q.getLast()]<nums[i]) q.pollLast();
q.add(i);
if(i>=k-1) res[i-k+1] = nums[q.getFirst()];
}
return res;
}
}
12.最小覆盖子串
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
- 对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量。 - 如果
s
中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC" 解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
示例 2:
输入:s = "a", t = "a" 输出:"a" 解释:整个字符串 s 是最小覆盖子串。
示例 3:
输入: s = "a", t = "aa" 输出: "" 解释: t 中两个字符 'a' 均应包含在 s 的子串中, 因此没有符合条件的子字符串,返回空字符串。
提示:
m == s.length
n == t.length
1 <= m, n <= 105
s
和t
由英文字母组成
class Solution {
public String minWindow(String s, String t) {
if(s.length()<t.length()) return "";
int[] s_cnt = new int[128];
int[] t_cnt = new int[128];
for(char c :t.toCharArray()) t_cnt[c]++;
int res = 100010;
int left = 0;
for(int l=0,r=0;r<s.length();r++){
s_cnt[s.charAt(r)]++;
while(l<=r&&check(s_cnt,t_cnt)){
if(r-l+1<res){
res = r-l+1;
left = l;
}
s_cnt[s.charAt(l++)]--;
}
}
if(res==100010) return "";
return s.substring(left,left+res);
}
public boolean check(int[] s_cnt,int[] t_cnt){
for(int i=0;i<128;i++){
if(s_cnt[i]<t_cnt[i]) return false;
}
return true;
}
}
13.最大子数组和
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1] 输出:1
示例 3:
输入:nums = [5,4,-1,7,8] 输出:23
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
进阶:如果你已经实现复杂度为 O(n)
的解法,尝试使用更为精妙的 分治法 求解。
class Solution {
public int maxSubArray(int[] nums) {
for(int i=1;i<nums.length;i++){
nums[i] = Math.max(nums[i-1]+nums[i],nums[i]);
}
int res = - Integer.MAX_VALUE ;
for(int i=0;i<nums.length;i++){
res = Math.max(res,nums[i]);
}
return res;
}
}
14.合并区间
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]] 输出:[[1,5]] 解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));
List<int[]> res = new LinkedList();
res.add(intervals[0]);
for(int i=1;i<intervals.length;i++){
int l = intervals[i][0],r = intervals[i][1];
int[] old = res.get(res.size()-1);
int old_l = old[0],old_r = old[1];
if(l>old_r){
res.add(intervals[i]);
}else{
int mer_l = old_l,mer_r = Math.max(r,old_r);
res.remove(res.size()-1);
res.add(new int[]{mer_l,mer_r});
}
}
return res.toArray(new int[res.size()][]);
}
}
15.轮转数组
给定一个整数数组 nums
,将数组中的元素向右轮转 k
个位置,其中 k
是非负数。
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3 输出:[5,6,7,1,2,3,4]
解释: 向右轮转 1 步:[7,1,2,3,4,5,6]
向右轮转 2 步:[6,7,1,2,3,4,5]
向右轮转 3 步:[5,6,7,1,2,3,4]
示例 2:
输入:nums = [-1,-100,3,99], k = 2 输出:[3,99,-1,-100] 解释: 向右轮转 1 步: [99,-1,-100,3] 向右轮转 2 步: [3,99,-1,-100]
提示:
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
0 <= k <= 105
进阶:
- 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
- 你可以使用空间复杂度为
O(1)
的 原地 算法解决这个问题吗?
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
k = k%n;
reverse_array(0,n-1,nums);
reverse_array(0,k-1,nums);
reverse_array(k,n-1,nums);
}
public void reverse_array(int start,int end,int[] nums){
while(start<end){
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
}
16.除自身以外数组的乘积
给你一个整数数组 nums
,返回 数组 answer
,其中 answer[i]
等于 nums
中除 nums[i]
之外其余各元素的乘积 。
题目数据 保证 数组 nums
之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请 不要使用除法,且在 O(n)
时间复杂度内完成此题。
示例 1:
输入: nums =[1,2,3,4]
输出:[24,12,8,6]
示例 2:
输入: nums = [-1,1,0,-3,3] 输出: [0,0,9,0,0]
提示:
2 <= nums.length <= 105
-30 <= nums[i] <= 30
- 输入 保证 数组
answer[i]
在 32 位 整数范围内
进阶:你可以在 O(1)
的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] pre = new int[nums.length];
int[] suff = new int[nums.length];
int[] res = new int[nums.length];
for(int i=0;i<n;i++) res[i] = 1;
pre[0] = nums[0];
for(int i=1;i<n;i++) pre[i] = pre[i-1]*nums[i];
suff[n-1] = nums[n-1];
for(int i=n-2;i>=0;i--) suff[i] = suff[i+1]*nums[i];
for(int i=0;i<n;i++){
if(i>0){
res[i] *= pre[i-1];
}
if(i<n-1){
res[i] *= suff[i+1];
}
}
return res;
}
}
17.缺失的第一个正数
给你一个未排序的整数数组 nums
,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n)
并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0] 输出:3 解释:范围 [1,2] 中的数字都在数组中。
示例 2:
输入:nums = [3,4,-1,1] 输出:2 解释:1 在数组中,但 2 没有。
示例 3:
输入:nums = [7,8,9,11,12] 输出:1 解释:最小的正数 1 没有出现。
提示:
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
class Solution {
public int firstMissingPositive(int[] nums) {
int n = nums.length;
for(int i=0;i<n;i++){
while(1<=nums[i]&&nums[i]<=n&&nums[i]!=nums[nums[i]-1]){
int temp = nums[i];
nums[i] = nums[temp-1];
nums[temp-1] = temp;
}
}
for(int i=0;i<n;i++){
if(nums[i]!=i+1){
return i+1;
}
}
return n+1;
}
}
18.矩阵置零
给定一个 m x n
的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
示例 1:
输入:matrix = [[1,1,1],[1,0,1],[1,1,1]] 输出:[[1,0,1],[0,0,0],[1,0,1]]
示例 2:
输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]] 输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]
提示:
m == matrix.length
n == matrix[0].length
1 <= m, n <= 200
-231 <= matrix[i][j] <= 231 - 1
进阶:
- 一个直观的解决方案是使用
O(mn)
的额外空间,但这并不是一个好的解决方案。 - 一个简单的改进方案是使用
O(m + n)
的额外空间,但这仍然不是最好的解决方案。 - 你能想出一个仅使用常量空间的解决方案吗?
class Solution {
public void setZeroes(int[][] matrix) {
int m = matrix.length,n=matrix[0].length;
int[] raw = new int[m];
int[] column = new int[n];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(matrix[i][j]==0){
raw[i] = 1;
column[j] = 1;
}
}
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(raw[i]==1||column[j]==1){
matrix[i][j] = 0;
}
}
}
return ;
}
}
19.螺旋矩阵
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] 输出:[1,2,3,4,8,12,11,10,9,5,6,7]
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
if(matrix==null||matrix.length==0||matrix[0].length==0) return null;
List<Integer> res = new LinkedList();
int m = matrix.length,n = matrix[0].length;
int left = 0,top=0,right=n-1,bottom=m-1;
while(left<=right&&top<=bottom){
for(int i=left;i<=right;i++){
res.add(matrix[top][i]);
}
for(int i=top+1;i<=bottom;i++){
res.add(matrix[i][right]);
}
if(left<right&&top<bottom){
for(int i= right-1;i>=left;i--){
res.add(matrix[bottom][i]);
}
for(int i=bottom-1;i>top;i--){
res.add(matrix[i][left]);
}
}
top++;
left++;
bottom--;
right--;
}
return res;
}
}
20.旋转图像
给定一个 n × n 的二维矩阵 matrix
表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:
输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]] 输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
提示:
n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000