第318场周赛
本周周赛答得不太好,只acc一道,第二第三题均超时
优化:如果是对数组原地操作
移动0就不需要辅助数组,使用快慢指针,fast遇到0的元素跳过,否则,复制给slow指针
然后,将slow后面的元素都复制给0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void moveVal (int nums[],int val) { int slow=0 ; int fast=0 ; int n=nums.length; while (fast<n){ if (nums[fast]!=val){ nums[slow++]=nums[fast]; } fast++; } for (int i=slow;i<n;i++){ nums[i]=val; } }
滑动窗口
我在做的时候,滑动窗口,用HashSet存储滑动窗口里面的内容,满足条件,循环计算HashSet的和,计算答案。 –> 超时
再试一下:
预先准备好前缀和数组,再使用滑动窗口 –> 可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public long maximumSubarraySum (int [] nums, int k) { int n=nums.length; long sum[]=new long [n]; sum[0 ]=nums[0 ]; for (int i=1 ;i<n;i++){ sum[i]=sum[i-1 ]+nums[i]; } int left=0 ; int right=0 ; HashSet<Integer> set=new HashSet <Integer>(); long ans=0 ; while (right<n){ if (set.contains(nums[right])){ set.remove(nums[left]); left++; }else { set.add(nums[right]); right++; if (set.size()>k){ set.remove(nums[left]); left++; } if (set.size()==k){ long temp=left==0 ?sum[right-1 ]:sum[right-1 ]-sum[left-1 ]; ans=ans<temp?temp:ans; } } } return ans; }
拓展:
变长滑动窗口:字符串
最小覆盖子串
变长滑动窗口:数组
最短超串
注:返回null和返回空数组new int[0]是不同的
定长滑动窗口:异位词
字符串的排列
字符串中的变位词
定长滑动窗口:异位词的位置 6. 438. 找到字符串中所有字母异位词 题:https://leetcode.cn/problems/find-all-anagrams-in-a-string
剑指 Offer II 015. 字符串中的所有变位词 题:https://leetcode.cn/problems/VabMRr
做题时,没想到用堆,超时
使用两个堆,使用左右指针维护堆元素
注意:一个工人不能进入两个堆
一定是一个工厂修理这一段距离上的机器人。
原问题:n个工厂修理m个机器人
子问题:1个工厂修了x个机器人,那么n-1个工厂修理m-x个机器人
找子问题很关键
方法1:记忆化搜索
定义 f(i,j)表示用第 i个及其右侧的工厂,修理第 j 个及其右侧的机器人,机器人移动的最小总距离。
j=m return 0
i=n-1 表示使用最后一个工厂修理m-j个机器人,如果工厂剩余修理机器人的数量小于m-j,则不合法
枚举第 i 个工厂修了 k个机器人,则有 $f(i,j) = \min\limits_{k}^{}{f(i+1,j+k) + \text{cost}(i,j,k)}$。
这里 $\text{cost}(i,j,k)$ 表示第 i 个工厂修复从 j 到 j+k-1 的机器人,移动距离就是这些机器人到第 i 个工厂的距离之和。
注意 $k\le\textit{limit}$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { int m; int n; static final long VALUE=100000000000L ; public long minimumTotalDistance (List<Integer> robot, int [][] factory) { Collections.sort(robot); Arrays.sort(factory,(a,b)->a[0 ]-b[0 ]); m=robot.size(); n=factory.length; return f(0 ,0 ,robot,factory); } long f (int i,int j,List<Integer> robot,int [][] factory) { if (j==m){ return 0 ; } if (i==n-1 ){ if (factory[i][1 ]<m-j){ return VALUE; }else { long s=0 ; for (int t=j;t<m;t++){ s+=Math.abs(factory[i][0 ]-robot.get(t)); } return s; } } long res=f(i+1 ,j,robot,factory); long cost=0 ; for (int k=1 ;k<=factory[i][1 ] && j+k-1 <m;k++){ cost+=Math.abs(factory[i][0 ]-robot.get(j+k-1 )); res=Math.min(res,cost+f(i+1 ,j+k,robot,factory)); } return res; } }
结果:超时
时间复杂度分析:
时间复杂度=O(状态个数)*O(单个状态转移次数)*O(单个状态转移时间)
状态个数:i的范围*j的范围
O=O(m*n)*O(m)*O(1)
方法2:递推
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public long minimumTotalDistance (List<Integer> robot, int [][] factory) { Collections.sort(robot); Arrays.sort(factory,(a,b)->a[0 ]-b[0 ]); int m=robot.size(); int n=factory.length; long dp[][]=new long [n][m]; long s=0 ; for (int i=0 ;i<Math.min(factory[0 ][1 ],m);i++){ s+=Math.abs(factory[0 ][0 ]-robot.get(i)); dp[0 ][i]=s; } if (m>factory[0 ][1 ]){ for (int i=factory[0 ][1 ];i<m;i++){ dp[0 ][i]=Integer.MAX_VALUE; } } for (int i=1 ;i<n;i++){ for (int j=0 ;j<m;j++){ dp[i][j]=dp[i-1 ][j]; s=0 ; for (int k=1 ;k<=Math.min(j,factory[i][1 ]);k++){ s+=Math.abs(factory[i][0 ]-robot.get(k)); dp[i][j]=Math.min(dp[i][j],s+dp[i-1 ][j-k]); } } } return dp[n-1 ][m-1 ]; }
类似题:1478安排邮筒
补:316场周赛 未解决
2449. 使数组相似的最少操作次数