78.给你一个整数数组 nums ,数组中的元素互不相同。返回该数组所有可能的子集(幂集)。
解集不能包含重复的子集。你可以按任意顺序返回解集。
迭代法实现子集枚举:
class Solution {
//我们用 1 表示「在子集中」,0 表示不在子集中,那么每一个子集可以对应一个长度为 n 的 0/1序列,第 i 位表示 ai 是否在子集中。
List<Integer> t = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> subsets(int[] nums) {
int n = nums.length;
for (int mask = 0; mask < (1 << n); mask++) {//1 << n:1的二进制左移n位再转成10进制
t.clear();
for (int i = 0; i < n; i++) {
//https://blog.csdn.net/feiyu_diary/article/details/78802996
//用于判断mask的第i位是否为0
if ((mask & (1 << i)) != 0) {
t.add(nums[i]);
}
}
ans.add(new ArrayList<Integer>(t));
}
return ans;
}
}
递归法实现子集枚举:
class Solution {
List<Integer> t = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> subsets(int[] nums) {
dfs(0, nums);
return ans;
}
public void dfs(int cur, int[] nums) {
if (cur == nums.length) {
//记录答案
ans.add(new ArrayList<Integer>(t));
return;
}
//考虑选择当前位置(二进制当前位置为1)
t.add(nums[cur]);
dfs(cur + 1, nums);
t.remove(t.size() - 1);//再移出t中最后一个元素
//考虑不选择当前位置(二进制当前位置为0)
dfs(cur + 1, nums);
}
}
79.给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
dfs+回溯:
class Solution {
public boolean exist(char[][] board, String word) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (board[i][j] == word.charAt(0) && dfs(board, word, i, j, 0)) {
return true;
}
}
}
return false;
}
public boolean dfs(char[][] board, String word, int i, int j, int k) {
if (k == word.length()) {
return true;
}
if (i < 0 || j < 0 || i >= board.length || j >= board[i].length) {
return false;
}
if (word.charAt(k) != board[i][j]) {
return false;
}
char t = board[i][j];
board[i][j] = '0';//表示访问过了
//下一个位置所以k+1,然后ij的变化分别为一个点的四个方位
boolean res = dfs(board, word, i + 1, j, k + 1) ||dfs(board, word, i - 1, j, k + 1) ||
dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i, j - 1, k + 1);
board[i][j] = t;//还原
return res;
}
}
84.给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为1。求在该柱状图中,能够勾勒出来的矩形的最大面积。
单调栈:
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
int[] right = new int[n];
Deque<Integer> stack = new ArrayDeque<Integer>();
//单调递减栈
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
stack.pop();
}
left[i] = (stack.isEmpty() ? -1 : stack.peek());
stack.push(i);
}
stack.clear();
for (int i = n - 1; i >= 0; i--) {
while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
stack.pop();
}
right[i] = (stack.isEmpty() ? n : stack.peek());
stack.push(i);
}
int ans = 0;
for (int i = 0; i < n; i++) {
ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
}
单调栈 + 常数优化:
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
int[] right = new int[n];
Arrays.fill(right, n);
Deque<Integer> stack = new ArrayDeque<Integer>();
for (int i = 0; i < n; ++i) {
while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
right[stack.peek()] = i;
stack.pop();
}
left[i] = (stack.isEmpty() ? -1 : stack.peek());
stack.push(i);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
}
85.给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。(结合第84题)
暴力解法优化:
class Solution {
public int maximalRectangle(char[][] matrix) {
int n = matrix.length;
if(n == 0) return 0; //若n=0,不存在矩阵
int m = matrix[0].length;
int[][] matrix1 = new int[n][m];
for(int i = 0;i < m;i++){
if(matrix[0][i] == '1') matrix1[0][i] = 1;
}
for(int i = 1;i < n;i++){
for(int j = 0;j < m;j++){
if(matrix[i][j] == '1')
matrix1[i][j] = matrix1[i - 1][j] + 1;
else
matrix1[i][j] = 0;
}
}
int ans = 0;
for(int i = 0;i < n;i++){
for(int j = 0;j < m;j++){
//这一行计算的面积根本不会超过ans则进入下一行
if(matrix1[i][j] * m <= ans) continue;
int cnt = 1; //现在只有它自己
for(int k = j + 1;k < m;k++){
if(matrix1[i][k] < matrix1[i][j]) break;
cnt++;
}
for(int k = j - 1;k >= 0;k--){
if(matrix1[i][k] < matrix1[i][j]) break;
cnt++;
}
ans = Math.max(ans, cnt * matrix1[i][j]);
}
}
return ans;
}
}
类似于单调栈的方法:
class Solution {
public int maximalRectangle(char[][] matrix) {
if (matrix.length == 0 || matrix[0].length == 0) { //行数或列数为0,不存在矩阵
return 0;
}
int[] heights = new int[matrix[0].length];
int maxArea = 0; //初始化为0
for (int row = 0; row < matrix.length; row++) {
//遍历每一列,更新高度
for (int col = 0; col < matrix[0].length; col++) {
if (matrix[row][col] == '1') {
heights[col] += 1;
} else {
heights[col] = 0;
}
}
//调用函数更新面积
maxArea = Math.max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
public int largestRectangleArea(int[] heights) {
//求每个柱子的左边第一个小的柱子的下标
int[] leftLessMin = new int[heights.length];
leftLessMin[0] = -1; //第一个柱子前边没有柱子,所以赋值为 -1,便于计算面积
for (int i = 1; i < heights.length; i++) {
int l = i - 1; //当前柱子更小一些,进行左移
while (l >= 0 && heights[l] >= heights[i]) {
l = leftLessMin[l];
}
leftLessMin[i] = l;
}
//求每个柱子的右边第一个小的柱子的下标
int[] rightLessMin = new int[heights.length];
rightLessMin[heights.length - 1] = heights.length;
for (int i = heights.length - 2; i >= 0; i--) {
int r = i + 1;
while (r <= heights.length - 1 && heights[r] >= heights[i]) {
r = rightLessMin[r];
}
rightLessMin[i] = r;
}
//求包含每个柱子的矩形区域的最大面积,选出最大的
int maxArea = 0;
for (int i = 0; i < heights.length; i++) {
int area = (rightLessMin[i] - leftLessMin[i] - 1) * heights[i];
maxArea = Math.max(area, maxArea);
}
return maxArea;
}
}
单调栈+常数优化:
class Solution {
public int maximalRectangle(char[][] matrix) {
if (matrix.length == 0 || matrix[0].length == 0) { //行数或列数为0,不存在矩阵
return 0;
}
int[] heights = new int[matrix[0].length];
int maxArea = 0; //初始化为0
for (int row = 0; row < matrix.length; row++) {
//遍历每一列,更新高度
for (int col = 0; col < matrix[0].length; col++) {
if (matrix[row][col] == '1') {
heights[col] += 1;
} else {
heights[col] = 0;
}
}
//调用函数更新面积
maxArea = Math.max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
int[] right = new int[n];
Arrays.fill(right, n);
Deque<Integer> stack = new ArrayDeque<Integer>();
for (int i = 0; i < n; ++i) {
while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
right[stack.peek()] = i;
stack.pop();
}
left[i] = (stack.isEmpty() ? -1 : stack.peek());
stack.push(i);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
}