本次题目
-
-
- 75 颜色分类
- 76 最小覆盖子串
- 78 子集
- 79 单词搜索
- 84 柱状图中最大的矩形
- 85 最大矩形
- 94 二叉树的中序遍历
- 96 不同的二叉搜索树
- 98 验证二叉搜索树
- 101 对称二叉树
75 颜色分类
- 快排,选择最左为哨兵,循环时先移动右指针,递归时跳过哨兵
class Solution {
public void sortColors(int[] nums) {
quickSort(nums, 0, nums.length - 1);
}
private void quickSort(int[] nums, int start, int end){
if(end - start < 1) return;
int i = start;
int j = end;
while(i < j){
while(i < j && nums[j] >= nums[start]) j--;
while(i < j && nums[i] <= nums[start]) i++;
swap(nums, i, j);
}
swap(nums, i, start);
quickSort(nums, start, i - 1);
quickSort(nums, i + 1, end);
}
private void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
- 双指针,左右指针分别从数组两头出发,遍历一次数组,遇到0与左指针位置交换,左指针右移;遇到2与右指针位置交换,右指针左移(这里需要判断交换后当前遍历位置是否为2,是则继续交换,0则与左指针交换)。
class Solution {
public void sortColors(int[] nums) {
int left = 0;
int right = nums.length - 1;
for(int i = 0; i <= right; i++){
while(i <= right && nums[i] == 2){
swap(nums, i, right--);
}
if(nums[i] == 0){
swap(nums, i, left++);
}
}
}
private void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
76 最小覆盖子串
- 滑动窗口,之前做过,使用StringBuilder处理字符串,使用哈希表存储字符串t的字符及出现次数,左右指针都从字符串s开头出发,右指针向右遍历,如果哈希表中有该字符,则对应次数减1,若次数减为0则一个字符满足,记录为flag。当哈希表中所有字符都满足时判断左指针是否向右移动缩小窗口,若左指针指向字符不是哈希表中字符或次数小于0则向右移动,否则不移动,计算长度并更新最短长度和子串。
- 注意:求StringBuilder的长度为length(),同字符串。
- 时间复杂度O(|字符集大小| * s + t),空间复杂度O(|字符集大小|)
class Solution {
public String minWindow(String s, String t) {
StringBuilder s1 = new StringBuilder(s);
StringBuilder t1 = new StringBuilder(t);
int leng = Integer.MAX_VALUE;
String result = "";
Map<Character, Integer> map = new HashMap<>();
for(int i = 0; i < t1.length(); i++){
if(!map.containsKey(t1.charAt(i))){
map.put(t1.charAt(i), 0);
}
map.put(t1.charAt(i), map.get(t1.charAt(i)) + 1);
}
int left = 0;
int right = 0;
int flag = 0;
for(;right < s1.length(); right++){
if(map.containsKey(s1.charAt(right))){
int num = map.get(s1.charAt(right)) - 1;
map.put(s1.charAt(right), num);
if(num == 0) flag += 1;
}
if(flag == map.size()){
while(!map.containsKey(s1.charAt(left)) || (map.containsKey(s1.charAt(left)) && map.get(s1.charAt(left)) < 0)){
if(map.containsKey(s1.charAt(left))){
map.put(s1.charAt(left), map.get(s1.charAt(left)) + 1);
}
left++;
}
if(leng > right - left + 1){
leng = right - left + 1;
result = s1.substring(left, right + 1);
}
}
}
return result;
}
}
78 子集
- 回溯,之前做过,定义start表示当前从数组第几位开始。
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
backtracking(nums, 0, result, path);
return result;
}
private void backtracking(int[] nums, int start, List<List<Integer>> result, List<Integer> path){
result.add(new ArrayList(path));
if(start >= nums.length) return;
for(int i = start; i < nums.length; i++){
path.add(nums[i]);
backtracking(nums, i + 1, result, path);
path.remove(path.size() - 1);
}
}
}
79 单词搜索
- 回溯,参考剑指 Offer 12 矩阵中的路径,定义当前位置和已匹配的字符个数,当不匹配时回溯,否则继续递归直到遍历结束,定义已使用的字符,递归时跳过。
- 注意:在回溯函数外遍历起点,终止条件顺序不能乱。
- 时间复杂度O(mn*3^L),空间复杂度O(mn),二维数组m行n列,字符串长度L
class Solution {
public boolean exist(char[][] board, String word) {
boolean[][] used = new boolean[board.length][board[0].length];
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[i].length; j++){
boolean flag = backtracking(board, used, word, i, j, 0);
if(flag) return true;
}
}
return false;
}
private boolean backtracking(char[][] board, boolean[][] used, String word, int x, int y, int z){
if(used[x][y]) return false;
if(board[x][y] != word.charAt(z)) return false;
if(word.length() == z + 1) return true;
used[x][y] = true;
if(x + 1 < board.length){
boolean down = backtracking(board, used, word, x + 1, y, z + 1);
if(down) return true;
}
if(x - 1 >= 0){
boolean up = backtracking(board, used, word, x - 1, y, z + 1);
if(up) return true;
}
if(y - 1 >= 0){
boolean left = backtracking(board, used, word, x, y - 1, z + 1);
if(left) return true;
}
if(y + 1 < board[x].length){
boolean right = backtracking(board, used, word, x, y + 1, z + 1);
if(right) return true;
}
used[x][y] = false;
return false;
}
}
84 柱状图中最大的矩形
class Solution {
public int largestRectangleArea(int[] heights) {
Deque<Integer> stack = new LinkedList<>();
int[] heights2 = new int[heights.length + 2];
heights2[0] = 0;
for(int i = 0; i < heights.length; i++){
heights2[i + 1] = heights[i];
}
heights2[heights2.length - 1] = 0;
stack.push(0);
int sum = 0;
for(int i = 1; i < heights2.length; i++){
int top = stack.peek();
if(heights2[i] > heights2[top]){
stack.push(i);
}else if(heights2[i] == heights2[top]){
stack.pop();
stack.push(i);
}else{
while(!stack.isEmpty() && heights2[i] < heights2[stack.peek()]){
int mid = stack.pop();
if(!stack.isEmpty()){
int h = heights2[mid];
int w = i - stack.peek() - 1;
sum = Math.max(sum, h * w);
}
}
stack.push(i);
}
}
return sum;
}
}
85 最大矩形
- 对比上题84 柱状图中最大的矩形,本题需要先将矩阵转为柱状图,定义矩阵每个元素左边连续1的数量为
left[i] [j]
,针对每一列使用单调栈进行计算。
class Solution {
public int maximalRectangle(char[][] matrix) {
int m = matrix.length;
if(m == 0) return 0;
int n = matrix[0].length;
int[][] left = new int[m + 2][n];
for(int i = 1; i < m + 1; i++){
for(int j = 0; j < n; j++){
if(matrix[i - 1][j] == '1'){
left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;
}
}
}
Deque<Integer> stack = new LinkedList<>();
int max = 0;
for(int j = 0; j < n; j++){
stack.push(0);
for(int i = 0; i < m + 2; i++){
if(stack.isEmpty()){
stack.push(i);
}else{
int top = stack.peek();
if(left[top][j] < left[i][j]){
stack.push(i);
}else if(left[top][j] == left[i][j]){
stack.pop();
stack.push(i);
}else{
while(!stack.isEmpty() && left[stack.peek()][j] > left[i][j]){
int mid = stack.pop();
if(!stack.isEmpty()){
int h = left[mid][j];
int w = i - stack.peek() - 1;
max = Math.max(max, h * w);
}
}
stack.push(i);
}
}
}
}
return max;
}
}
94 二叉树的中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
inorder(root, result);
return result;
}
private void inorder(TreeNode root, List<Integer> result){
if(root == null) return;
inorder(root.left, result);
result.add(root.val);
inorder(root.right, result);
}
}
96 不同的二叉搜索树
class Solution {
public int numTrees(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= i; j++){
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
}
98 验证二叉搜索树
- 递归,之前做过,二叉搜索树中序遍历为升序,记录上一个节点值并和当前值进行对比。
class Solution {
TreeNode pre = null;
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
boolean left = isValidBST(root.left);
if(pre != null && pre.val >= root.val) return false;
pre = root;
boolean right = isValidBST(root.right);
return left && right;
}
}
101 对称二叉树
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return false;
return compareNode(root.left, root.right);
}
private boolean compareNode(TreeNode left, TreeNode right){
if(left == null && right == null) return true;
if(left == null || right == null) return false;
if(left.val != right.val) return false;
boolean l = compareNode(left.left, right.right);
if(!l) return false;
boolean r = compareNode(left.right, right.left);
return l && r;
}
}