首先有个很大的进步,看见困难题我没选择做逃兵跑路,这点起码是进步了,虽然算法能力还是那么拉,但是起码敢不自量力地分析一下。。。还能看题解理解下。
先找题解中最简单地一种超时方法开始理解,使用动态规划:
定义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<int[]> q = new PriorityQueue<int[]>((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<isConnected.length;i++){
if(!used[i]){
dfs(i,isConnected);
res++;}
}
return res;
}
public void dfs(int i,int[][] isConnected){
used[i]=true;
for(int j=0;j<isConnected[0].length;j++){
if(!used[j]&&isConnected[i][j]==1) dfs(j,isConnected);
}
}
}