
首先有个很大的进步,看见困难题我没选择做逃兵跑路,这点起码是进步了,虽然算法能力还是那么拉,但是起码敢不自量力地分析一下。。。还能看题解理解下。
先找题解中最简单地一种超时方法开始理解,使用动态规划:
定义dp:dp[i]:前i个箱子所需的最小行程
初始化:明显有dp[0]=0,其他的需要选最大值,因为要维护最小值
状态转移公式:dp[i]=dp[j-1]+cost(j,i);cost(j,i)代表j到i范围内的箱子所需要的行程
cost(i,j)怎么求:首先出去和回来都需要一次行程,初始化为2,遍历范围的箱子,如果有相同连续码头的箱子,就可以一次性都放了,加1,没连续遇见一个新码头就要加1
箱子需要遍历,范围需要遍历两次,超时,但是比较好理解
class Solution {public int boxDelivering(int[][] boxes, int portsCount, int maxBoxes, int maxWeight) {int len=boxes.length;int[] dp=new int[len+1];//dp[i]:运送前i个箱子所需要的最少行程Arrays.fill(dp,Integer.MAX_VALUE);dp[0]=0;//初始化for(int i=1;i<=len;i++){int sum=0;//保证重量不超过最大值for(int j=i;j>=1&&j>=i-maxBoxes+1;j--){//保证数量不超过最大值sum+=boxes[j-1][1];//累加重量if(sum>maxWeight) break;dp[i]=Math.min(dp[i],dp[j-1]+cost(j,i,boxes));}}return dp[len];}public int cost(int l,int r,int[][] boxes){int port=2;//仓库出去和回来都要一次行程int pre=boxes[l-1][0];//记录前一个箱子目标码头while(++l<=r){//遍历这个范围的箱子if(boxes[l-1][0]==pre) continue;//和前面的箱子相同就不用行程port++;//不然就要一次行程pre=boxes[l-1][0];//更新前一个码头}return port;}
}

这里的dp可以发现是维护一个滑动窗口中的最小值,第一次见,详细分析见 力扣大佬题解
总之就是需要优化每次找最小值的时间,我选择使用优先队列,感觉好理解一点,看了很久,这题有点超出我水平了,溜了,有缘回来再看。
class Solution {public int boxDelivering(int[][] boxes, int portsCount, int maxBoxes, int maxWeight) {int len=boxes.length;int[] dp=new int[len+1];//dp[i]:运送前i个箱子所需要的最少行程Arrays.fill(dp,Integer.MAX_VALUE);dp[0]=0;//初始化PriorityQueue q = new PriorityQueue((a, b)->a[1] - b[1]);//数组中保存的分别是i下标,最少次数,重量int dif=0;//差值int wei=0;//保存重量for(int i=1;i<=len;i++){int cur = dp[i-1] + 2;dif += i >= 2 && boxes[i - 1][0] != boxes[i - 2][0] ? 1 : 0;//如果相同,代表多加了一次行程wei += boxes[i - 1][1]; //保存重量q.add(new int[]{i, cur - dif, boxes[i - 1][1] - wei}); while (q.peek()[0] <= i - maxBoxes || q.peek()[2] + wei > maxWeight) q.poll();//超载dp[i] = q.peek()[1] + dif; }return dp[len];}
}

经典的搜索题,写了好几遍了
遍历所有城市,使用used标志该城市是否访问过,没访问过就进行深搜,找到和他相连的城市都搜一遍。
class Solution {boolean[] used;public int findCircleNum(int[][] isConnected) {int res=0;//记录省份数量used=new boolean[isConnected.length];for(int i=0;i