算法刷题1

Posted on 2022-06-21 18:50  小权coding  阅读(73)  评论(0)    收藏  举报

题目一

给定两个非负数组x和hp,长度都是N,再给定一个正数rangex有序,x[i]表示i号怪兽在x轴上的位置;hp[i]表示i号怪兽的血量 range表示法师如果站在x位置,用AOE技能打到的范围是:[x-range,x+range],被打到的每只怪兽损失1点血量返回要把所有怪兽血量清空,至少需要释放多少次AOE技能?

题目大意:假设一个数组为[5,7,6,4,2,9,5,4],AOE的范围是4,我们应该关注边缘5是怎么没有的,需要AOE在5的边缘打5次这样一定最省,打完5次数组的血量如下[0,2,1,-1,2,9,5,4],小于0就代表血量已经为空了,然后依次向后血量不为0的进行遍历,直到所有的血量都为0为止。

image-20220621094800683

如图所示,此时AOE需要释放5+2+9=16次技能,

解法一:暴力解,假设AOE在每一个位置都放,类似一个全排列的方式进行验证。

代码如下:

 

解法二:为了避免每次减掉的数字都遍历使用使用线段shu来进行求解,时间复杂度O(N*logN).

代码如下:

 

题目二

给定一个 m x n 整数矩阵 matrix ,找出其中最长递增路径的长度。对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线 方向上移动或移动到边界外(即不允许环绕)。

示例:给定一个mxn整数矩阵matrix ,找出其中最长递增路径的长度。

image-20220621104358236

 输入:matrix = [[9,9,4],[6,6,8],[2,1,1]]
 输出:4
 解释:最长递增路径为 [1, 2, 6, 9]。

解法一:暴力递归,一个位置一个位置的去试,时间复杂度高,会超出时间限制。

代码如下:

  public int longestIncreasingPath(int[][] matrix) {
         int ans = 0 ;
         int N = matrix.length;
         int M = matrix[0].length;
         //你可以在每一个位置上都试上一遍
         for (int i = 0 ; i < N ; i++){
             for (int j = 0 ; j < N ; j++){
                 ans = Math.max(ans,process(matrix,i,j));
            }
        }
         return ans;
    }
     //从m[i][j]开始出发
     public int process(int[][] matrix ,int i ,int j){
        //边界判断
         if (i < 0 || i == matrix.length || j < 0 || j == matrix[0].length){
             return 0;
        }
         //上下左右暴力尝试
         int up = i > 0 && matrix[i][j] < matrix[i - 1][j] ? process(matrix ,i - 1,j) : 0 ;
         int down = i+1 != matrix.length && matrix[i][j] < matrix[i + 1][j] ? process(matrix,i + 1,j) : 0;
         int left = j > 0 && matrix[i][j] < matrix[i][j-1] ? process(matrix,i,j - 1) : 0;
         int right = j + 1 != matrix[0].length && matrix[i][j] < matrix[i][j + 1] ? process(matrix,i,j + 1) : 0;
         return Math.max(Math.max(left,right),Math.max(up,down)) + 1;
    }
 }

image-20220621123134128

解法二:记忆化搜索,因为答案只和 i,j 的位置有关,如果 i 和 j 确定了那么答案也就确定了,准备一个dp表记录答案,直接通过力扣。

代码如下:

  public int longestIncreasingPath(int[][] matrix) {
         int ans = 0 ;
         int N = matrix.length;
         int M = matrix[0].length;
         //你可以在每一个位置上都试上一遍
         int[][] dp = new int[N][M];
         for (int i = 0 ; i < N ; i++){
             for (int j = 0 ; j < M ; j++){
                 ans = Math.max(ans,process2(matrix,i,j,dp));
            }
        }
         return ans;
    }
     public int process2(int[][]matrix ,int i , int j , int[][] dp){
         //看缓存表里是否存在
         if (dp[i][j] != 0){
             return dp[i][j];
        }
         //边界判断
         if (i < 0 || i == matrix.length || j < 0 || j == matrix[0].length){
             return 0;
        }
         int up = i > 0 && matrix[i][j] < matrix[i - 1][j] ? process2(matrix ,i - 1,j,dp) : 0 ;
         int down = i+1 != matrix.length && matrix[i][j] < matrix[i + 1][j] ? process2(matrix,i + 1,j,dp) : 0;
         int left = j > 0 && matrix[i][j] < matrix[i][j-1] ? process2(matrix,i,j - 1,dp) : 0;
         int right = j + 1 != matrix[0].length && matrix[i][j] < matrix[i][j + 1] ? process2(matrix,i,j + 1,dp) : 0;
         int ans = Math.max(Math.max(left,right),Math.max(up,down)) + 1;
         //缓存
         dp[i][j] = ans;
         return ans;
    }
 }

image-20220621124609733

题目三

链接:https://leetcode.cn/problems/target-sum

给你一个整数数组 nums 和一个整数 target 。向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :

 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例:

输入:nums = [1,1,1,1,1], target = 3 输出:5 解释:一共有 5 种方法让最终目标和为 3 。 -1 + 1 + 1 + 1 + 1 = 3 +1 - 1 + 1 + 1 + 1 = 3 +1 + 1 - 1 + 1 + 1 = 3 +1 + 1 + 1 - 1 + 1 = 3 +1 + 1 + 1 + 1 - 1 = 3

题解一:暴力递归,从左往右的尝试模型,每一个位置 + 和 - 都尝试一遍直到得到答案,求总数,时间复杂度较高。

代码如下:

   public int findTargetSumWays(int[] nums, int target) {
         //如果正数和都小于target肯定没有方案
         int sum = 0 ;
         for (int i = 0 ; i < nums.length ;i++){
             if (nums[i] >= 0){
                 sum += nums[i];
            }else {
                 nums[i]=-nums[i];
                 sum += nums[i];
            }
        }
         //如何奇偶性不一致也没有方案
         if (target % 2 != sum % 2 || target > sum){
             return 0;
        }
         return process(nums,0,target);
    }
     public int process(int[] nums ,int L ,int rest){
         if (L == nums.length){
             return rest == 0 ? 1 : 0;
        }
         return process(nums,L+1,rest-nums[L])+process(nums,L+1,nums[L]+rest);
    }
 }

image-20220621130821479

题解二:缓存法,因为答案只和L和rest有关,所有准备一张缓存表dp,不用重复算已经算过的了。

代码如下:

 

题目四

一个数组中只有两种字符'G'和'B’,可以让所有的G都放在左侧,所有的B都放在右侧, 或者可以让所有的G都放在右侧,所有的B都放在左侧, 但是只能在相邻字符之间进行交换操作,返回至少需要交换几次。

题解一:双指针问题,假设G在左边,B在右边,假设两个指针b1与b2,b1指向第一种方式要交换的位置,b2指向第二种方式要交换的位置。

代码如下:

 public static int minStep(String s){
//有两种方式让G在左,或者让G在右
if (s == null || s.equals("")){
return 0;
}
int step1 = 0 ;
int step2 = 0;
int b1 = 0 ;
int b2 = 0;
char[] str = s.toCharArray();
for (int i = 0 ; i < str.length ;i++){
//G在左
if (str[i]=='G'){
step1 += i-b1++;
}
//G在右
else {
step2 += i-b2++;
}
}
return Math.min(step1,step2);
}
}

题目五

给点一个非负整数num,如何不用循环语句,返回大于等于num,并且里num最近的2的某次方,注意整数为int范围的数。

示例如果num为7就返回8,如果为14就返回16,依次类推。

题解一:用位运算来解决问题,比如7对应的二进制位00000111,以第一个1为起点后面全部变成1,此时就变成了00000111然后再+1就变成了00001000对应的十进制就是8,这个例子不明显的话拿14为例,14的二进制为00001110,变成00001111最后再+1就变成了00010000,值就为16了。

代码如下:

public static int tableSizeFor(int n) {
n--;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return n + 1;
}

题目六

给定一个文件目录的路径,写一个函数统计这个目录下所有的文件数量并且返回,隐藏文件也算,但是文件夹不算。

题解1:给定文件目录,如果是文件夹进入栈,如果是文件就加1。

 public static int getFileNumber(String folderPath){
File root = new File(folderPath);
if (!root.isDirectory()&&!root.isFile()){
return 0;
}
//如果是文件直接返回答案1
if (root.isFile()){
return 1;
}
//准备一个栈存放文件夹
Stack<File> stack = new Stack<>();
stack.push(root);
int file = 0 ;
while (!stack.isEmpty()) {
File folder = stack.pop();
for (File next : folder.listFiles()) {
if (next.isFile()) {
file++;
}
if (next.isDirectory()) {
stack.push(next);
}
}
}
return file;
}

题目七

给定一个有序数组arr,代表坐落在X轴上面的点,给定一个正数K,代表绳子的长度返回绳子最多压中几个点?即使是边缘也算压中。

题解:滑动窗口,从最左开始向右滑,对比最多能压中的点数,L与R永远不会后退时间复杂度为O(N).

image-20220621145018680

image-20220621145031371

image-20220621145043452

image-20220621145053539

代码如下:

     public static int maxPoint(int[] arr ,int k){
         int L = 0;
         int R = 0;
         int N = arr.length;
         int max = 0;
         for (int i = 0 ; i < N ; i++){
             L = arr[i];
             R = arr[i] + k <= arr[N-1] ? arr[i] + k - 1 : arr[N-1];
             int left = L;
             int count = i;
             int ans = 0;
             while (left <= R){
                 left = arr[count++];
                 ans++;
            }
             max = Math.max(ans,max);
        }
         return max;
    }