LeetCode第77场双周赛(2022-04-31)

本文详细介绍了四道算法题目,包括统计字符串前缀、寻找最小平均差、计算未被保卫的网格单元数量以及模拟火灾扩散过程。通过Java代码实现,涉及字符串操作、数组处理、深度优先搜索和广度优先搜索等算法技巧,适合提升编程思维和算法能力。
摘要由CSDN通过智能技术生成

6051. 统计是给定字符串前缀的字符串数目

https://leetcode-cn.com/problems/count-prefixes-of-a-given-string/
在这里插入图片描述

思路:遍历words数组,利用字符串中的startWith()方法即可

class Solution {
  	public int countPrefixes(String[] words, String s) {
		int cnt=0;
		for(String word:words) {
			if(s.startsWith(word))
				cnt++;
		}
		return cnt;
   }
}
//O(kn) k是words数组中单词的平均长度
//O(1)

6052. 最小平均差

https://leetcode-cn.com/problems/minimum-average-difference/
在这里插入图片描述

思路:简单模拟题,遍历到某个下标i时,只需要知道nums[0…i]和nums[i+1,n-1]的和即可,然后求平均值。为了方便获得当前位置的累加和,利用前缀和数组,这样可以容易地获得nums[0…i]元素之和,对于nums[i+1,n-1]元素和可以利用总的和减去nums[0…i]元素之和获取。
注意点:和的数值可能很大,使用long类型,不然会数据溢出

class Solution {
   	 public int minimumAverageDifference(int[] nums) {
		 int n=nums.length;
		 long totalSum=0;
		 long[] pre=new long[n+1];
		 for(int i=0;i<n;i++) {
			 pre[i+1]=pre[i]+nums[i];
			 totalSum+=nums[i];
		 }
			
		 int ans=-1;
		 long minDif=Integer.MAX_VALUE;
		 for(int i=0;i<n;i++) {
			 long sum1=pre[i+1];
			 long sum2=totalSum-sum1;
			 long ave1=sum1/(i+1);
			 long ave2=n-i-1==0?0:sum2/(n-i-1);
			 long dif=Math.abs(ave1-ave2);
			 if(dif<minDif) {
				 minDif=dif;
				 ans=i;
			 }
		 }
		 return ans;
	 }
}
//O(n)
//O(n)

6053. 统计网格图中没有被保卫的格子数

https://leetcode-cn.com/problems/count-unguarded-cells-in-the-grid/
在这里插入图片描述

思路:dfs, 和一般的dfs不同,这里的dfs都是直来直往,没有拐弯抹角。使用一个visited数组记录网格中不同格子的情况,先根据guards数组和walls数组进行初始化,有警卫的位置用1表示,有墙的地方用2表示;然后遍历网格,遇到1时(警卫),开始向4个方向dfs搜索,对于可以看到的位置,在visited数组中用3表示,防止重复访问。遍历结束只会,判断visited数组中为0的个数即可

class Solution {
    int[][] visted;
	int m,n;
	int[][] g;
	int[][] w;
     public int countUnguarded(int m, int n, int[][] guards, int[][] walls) {
		  visted=new int[m][n];
		  for(int[] guard:guards) {
			  int i=guard[0];
			  int j=guard[1];
			  visted[i][j]=1;
		  }
		  for(int[] wall:walls) {
			  int i=wall[0];
			  int j=wall[1];
			  visted[i][j]=2;
		  }
		  this.m=m;
		  this.n=n;
		  this.g=guards;
		  this.w=walls;
		  for(int i=0;i<m;i++) {
			  for(int j=0;j<n;j++) {
				  if(visted[i][j]==1) {
					  	 dfs1(i+1,j);
						 dfs2(i-1,j);
						 dfs3(i, j+1);
						 dfs4(i, j-1);
				  }
			  }
		  }
		  int ans=0;
		  for(int i=0;i<m;i++) {
			  for(int j=0;j<n;j++)
				  if(visted[i][j]==0)
					  ans++;
		  }
		  return ans;
	 }
	 public void dfs1(int i,int j) {//向下看
		 if(i<0||i>=m||j<0||j>=n||visted[i][j]==1||visted[i][j]==2)
			 return;
		 visted[i][j]=3;
		 dfs1(i+1,j);
		
	 }
	 public void dfs2(int i,int j) {//向上看
		 if(i<0||i>=m||j<0||j>=n||visted[i][j]==1||visted[i][j]==2)
			 return;
		 visted[i][j]=3;
		 dfs2(i-1,j);
		
	 }
	 public void dfs3(int i,int j) {//向右看
		 if(i<0||i>=m||j<0||j>=n||visted[i][j]==1||visted[i][j]==2)
			 return;
		 visted[i][j]=3;
		 dfs3(i,j+1);
		
	 }
	 public void dfs4(int i,int j) {//向左看
		 if(i<0||i>=m||j<0||j>=n||visted[i][j]==1||visted[i][j]==2)
			 return;
		 visted[i][j]=3;
		 dfs4(i,j-1);
		
	 }	
}
//O(mn) 每个格子最多只会被遍历一次
//O(mn)

6054. 逃离火灾

https://leetcode-cn.com/problems/escape-the-spreading-fire/

在这里插入图片描述
在这里插入图片描述

思路:BFS+二分

几个关键点:

  1. 只保存新蔓延到的着火点
  2. 新蔓延到的着火的在每一次bfs后都要更新
class Solution {
    int[][] dirs={{0,-1},{0,1},{-1,0},{1,0}};//方向数组
    public int maximumMinutes(int[][] grid) {
        int m=grid.length,n=grid[0].length;
        int left=0,right=m*n;//最少最多的停留时间
        boolean canEscape=false;
        while(left<=right){
            //int mid=left+(right-left)/2;
            int mid=(left+right)/2;
            if(check(grid,mid)){
                left=mid+1;//安全->时间再待久一点
                canEscape=true;
            }   
            else
                right=mid-1;
        }
        if(!canEscape)//没有成功过
            return -1;
        else
            return left<m*n?left-1:(int)1e9;
        //0--left-1时间都是安全的  left时间不安全
    }
    public boolean check(int[][] grid,int minutes){
         int m=grid.length,n=grid[0].length;
         boolean[][] fire=new boolean[m][n];//表示某个位置是否有火
         ArrayList<int[]> firePoints=new ArrayList<>();//记录着火点
         for(int i=0;i<m;i++){
             for(int j=0;j<n;j++){
                 if(grid[i][j]==1){//网格值为1表示起火
                     fire[i][j]=true;//(i,j)位置着火
                     firePoints.add(new int[]{i,j});
                 }
             }
         }
         while(minutes>0&&firePoints.size()>0){//蔓延minutes分钟的火势 并且有蔓延点
             firePoints=spreadFire(grid,fire,firePoints);//firePoints保存新蔓延到的着火点
             minutes--;
         }
         boolean[][] vis=new boolean[m][n];
         ArrayList<int[]> q=new ArrayList<>();
         q.add(new int[]{0,0});
         vis[0][0]=true;
         while(q.size()>0){
              ArrayList<int[]> tmp=q;
              q=new ArrayList<>();
              for(int[] point:tmp){
                  if(!fire[point[0]][point[1]])//当前位置未着火
                  for(int[] dir:dirs){
                      int x=point[0]+dir[0];
                      int y=point[1]+dir[1];
                      if(x>=0&&x<m&&y>=0&&y<n&&!fire[x][y]&&grid[x][y]!=2&&!vis[x][y]){
                          if(x==m-1&&y==n-1)//达到右下角
                            return true;
                        vis[x][y]=true;
                        q.add(new int[]{x,y});//当前可以达到的未着火点 经过后面传播可以着火
                      }
                  }
                
              }
              firePoints=spreadFire(grid,fire,firePoints);//蔓延1分钟的火势
         }
         return false;
    }
   public ArrayList<int[]> spreadFire(int[][] grid, boolean[][] fire, ArrayList<int[]> firePoints) {
        int m=grid.length,n=grid[0].length;
        ArrayList<int[]> newFirePoints=new ArrayList<>();//新传播到的着火点
        for(int[] firePoint:firePoints){
            for(int[] dir:dirs){
                int x=firePoint[0]+dir[0];
                int y=firePoint[1]+dir[1];
                if(x>=0&&x<m&&y>=0&&y<n&&grid[x][y]!=2&&!fire[x][y]){//不出边界+不是墙+之前没有被点着
                    fire[x][y]=true;
                    newFirePoints.add(new int[]{x,y});
                }
            }
        }
        return newFirePoints;
   }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodePanda@GPF

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值