(算法题)Day-20230228
1. 滑动窗口
剑指 Offer 30. 包含min函数的栈
/**
 * 剑指 Offer 30. 包含min函数的栈
 */
class minStack {
   Stack<Integer> A, B;
   public minStack() {
      A = new Stack<>();
      B = new Stack<>();
   }
   public void push(int x) {
      A.add(x);
      if (B.empty() || B.peek() >= x) {
         B.add(x);
      }
   }
   public void pop() {
      if (A.pop().equals(B.peek())) {
         B.pop();
      }
   }
   public int top() {
      return A.peek();
   }
   public int min() {
      return B.peek();
   }
}
滑动窗口的最大值
思路:先得到窗口内数据的单调队列D,这样就可以将D中第一个数作为窗口内的最大值 放入结果数组中;然后迭代,对即将新加入的一个数n进行比较,删除D中比n小的数,得到结果数组
package hhh.slide_window;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Stack;
/**
 * @author hdbing
 * @create 2023-02-28 15:06
 */
public class SW01 {
   public static void main(String[] args) {
      int[] nums = {1, 3, -1, -3, 5, 3, 6, 7};
      int k = 3;
      int[] res = maxSlidingWindow(nums, k);
      for (int i : res) {
         System.out.println(i);
      }
   }
   /**
    * 剑指 Offer 59 - I. 滑动窗口的最大值(单调队列,清晰图解)
    * https://leetcode.cn/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/solution/mian-shi-ti-59-i-hua-dong-chuang-kou-de-zui-da-1-6/
    * @param nums
    * @param k
    * @return
    */
   static int[] maxSlidingWindow(int[] nums, int k) {
      if (nums.length == 0 || k == 0) return new int[0];
      Deque<Integer> deque = new LinkedList<>();
      int[] res = new int[nums.length - k + 1];
      for (int j = 0, i = 1 - k; j < nums.length; i++, j++) {
         // 删除 deque 中对应的 nums[i-1],避免重复添加当前最大值;但是结果其实都是一致的
         if (i > 0 && deque.peekFirst() == nums[i - 1]) {
            deque.removeFirst();
         }
         // 保持 deque 递减
         while (!deque.isEmpty() && deque.peekLast() < nums[j]) {
            deque.removeLast();
         }
         deque.addLast(nums[j]);
         // 记录窗口最大值
         if (i >= 0) {
            res[i] = deque.peekFirst();
         }
      }
      return res;
   }
}
剑指 Offer 48. 最长不含重复字符的子字符串
动态规划+哈希表
如果s="abcabcbb",\(s[i]\) 表示离 \(s[j]\) 最近的一个重复字符,如 j=3,则 i=0;
然后状态定义为:\(dp[j]\) 表示以 \(s[j]\) 为结尾的 “最长不重复子字符串” 的长度,如 \(dp[2]=3\),即子串 “abc”
这样就可以通过子串是否出现在 i 和 j 之间来定义状态转移方程,这里需要注意边界,在i 和 j之间则 \(d[j]=d[j-1]+1\),否则为 \(j-i\)
最后的问题就是如何计算索引 \(i\) ?采用哈希表在迭代时保存各个字符的索引,然后在需要时去寻找 \(i\) 即可
class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dic = new HashMap<>();
        int res = 0, tmp = 0;
        for(int j = 0; j < s.length(); j++) {
            int i = dic.getOrDefault(s.charAt(j), -1); // 获取索引 i
            dic.put(s.charAt(j), j); // 更新哈希表
            tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j]
            res = Math.max(res, tmp); // max(dp[j - 1], dp[j])
        }
        return res;
    }
}
2. 数组
合并两个有序数组
思路:从后往前赋值,然后迭代次数为 m+n
package hhh.array;
/**
 * @author hdbing
 * @create 2023-02-28 16:49
 */
public class a05 {
   public static void main(String[] args) {
      int[] nums1 = {1, 2, 3, 0, 0, 0};
      int m = 3;
      int[] nums2 = {2, 5, 6};
      int n = 3;
      mergeTwoArray(nums1, m, nums2, n);
      for (int i : nums1) {
         System.out.println(i);
      }
   }
   static void mergeTwoArray(int[] nums1, int m, int[] nums2, int n) {
      int i = m - 1;
      int j = n - 1;
      for (int k = m + n - 1; k >= 0; k--) {
         if (j < 0 || (i >= 0 && nums1[i] >= nums2[j])) {
            nums1[k] = nums1[i];
            i--;
         } else {
            nums1[k] = nums2[j];
            j--;
         }
      }
   }
}
岛屿的最大面积
思路:遍历然后 由深度优先搜索 迭代得到最大面积
package hhh.array;
/**
 * @author hdbing 岛屿的最大面积
 * @create 2023-02-28 18:46
 */
public class a06 {
	public static void main(String[] args) {
		int[][] grid = {{0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
				{0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0},
				{0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
				{0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0},
				{0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0},
				{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
				{0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0},
				{0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0}};
		int area = maxAreaOfIsland(grid);
		System.out.println(area);
	}
	static int maxAreaOfIsland(int[][] grid) {
		int ans = 0;
		for (int i = 0; i < grid.length; i++) {
			for (int j = 0; j < grid[0].length; j++) {
				ans = Math.max(ans, dfs(grid, i, j));
			}
		}
		return ans;
	}
	static int dfs(int[][] grid, int cur_i, int cur_j) {
		if (cur_i < 0 || cur_j < 0 || cur_i == grid.length || cur_j == grid[0].length || (grid[cur_i][cur_j] != 1)) {
			return 0;
		}
		// 将岛屿置为 0 避免重复遍历
		grid[cur_i][cur_j] = 0;
		// 上下左右 四个方向
		int[] di = {0, 0, 1, -1};
		int[] dj = {1, -1, 0, 0};
		int ans = 1;
		for (int index = 0; index < 4; index++) {
			int nex_i = cur_i + di[index], next_j = cur_j + dj[index];
			ans += dfs(grid, nex_i, next_j); // dfs遍历
		}
		return ans;
	}
}
移除元素
思路:快慢指针,不是目标时 同时加1,遇见目标时只需要快指针加1
package hhh.array;
/**
 * @author hdbing
 * @create 2022-10-04 18:45
 */
public class a03 {
	public static void main(String[] args) {
		int[] nums = {1};
		Solution s=new Solution();
		System.out.println(s.removeElement(nums,1));
	}
}
class Solution {
	public int removeElement(int[] nums, int val) {
		int fastIdx = 0;
		int slowIdx = 0;
		for(int i=0; i<nums.length; i++){
			if (nums[i]!=val){
				fastIdx+=1;
				slowIdx+=1;
			}else{
				fastIdx+=1;
			}
			nums[slowIdx]=nums[fastIdx];
			if (fastIdx==nums.length-1){
				return slowIdx;
			}
		}
		return nums.length;
	}
}
有序数组的平方
思路:快慢指针,一个从头开始,一个从尾开始,然后比较大小 移动指针
class Solution {
    public int[] sortedSquares(int[] nums) {
        int right = nums.length - 1;
        int left = 0;
        int[] result = new int[nums.length];
        int index = result.length - 1;
        while (left <= right) {
            if (nums[left] * nums[left] > nums[right] * nums[right]) {
                // 正数的相对位置是不变的, 需要调整的是负数平方后的相对位置
                result[index--] = nums[left] * nums[left];
                ++left;
            } else {
                result[index--] = nums[right] * nums[right];
                --right;
            }
        }
        return result;
    }
}
长度最小的子数组
思路:快慢指针,不满足条件移动快指针,满足条件就移动慢指针
class Solution {
    // 滑动窗口
    public int minSubArrayLen(int s, int[] nums) {
        int left = 0;
        int sum = 0;
        int result = Integer.MAX_VALUE;
        for (int right = 0; right < nums.length; right++) {
            sum += nums[right];
            while (sum >= s) {
                result = Math.min(result, right - left + 1);
                sum -= nums[left++];
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

                
            
        
浙公网安备 33010602011771号