emmm今天的我还是很菜,只能做前两道题,第三道之前没见过,没有任何头绪来解题,尝试了几种方法也不行,第四个根本不知道怎么处理。。。
原本前两道题都可以一次AC的,但是因为自己的粗心,导致第二个题逻辑出现错误,因为没注意错误案例,只好又提交了一次看案例(白送一次。。。)
前两个题还是非常基础的,后两个题的解法明天要好好学习一下。
第一题
思路
简单来说就是[left,right]
是否在ranges数组内所有区间组成的大区间内,所以可以把题目简化为:
- 依次遍历
[left,right]
中的每一个元素,检查其是否在ranges的某个区间内,如果存在,则遍历下一个元素,如果不存在,直接返回false;
时间复杂度O( (right-left+1) * (ranges.length) )
也就是[left,right]的元素数 × ranges数组的长度
代码
public boolean isCovered(int[][] ranges, int left, int right) {
int row = ranges.length;
int col = ranges[0].length;
int sign = 0;
for (int i=left;i<=right;i++)
{
sign = 0;
for (int j=0;j<row;j++)
{
if (i>=ranges[j][0] && i<= ranges[j][1])
{
sign = 1;
break;
}
}
// System.out.println(i);
if (sign == 0)
return false;
}
return true;
}
第二题
思路
因为涉及到循环,所以先判断是否需要循环?
需要循环的话,需要循环多少次?
然后使用k减去循环所需要的数量,再对chalk数组依次遍历即可。
需要注意的是,因为chalk的长度最大值
和chalk[i]的最大值
均为
1
0
5
10^5
105,所以chalk的元素和最大值
为
1
0
10
10^{10}
1010,超出int的范围
了,可以通过在循环中实时检查是否大于k来避免溢出(一旦sum超过k,那么sum的值就没用了,不超过的话也就不会溢出)
;
算法步骤:
- 计算chalk数组的元素和,并实时检查sum是否大于k,大于k的话直接break;
- 计算循环的次数,然后k减去循环所需要的数量;
- 顺序遍历chalk数组,需要注意的是,题目中提到要
严格小于
才是当前学生,所以只使用<
;
代码
public int chalkReplacer(int[] chalk, int k) {
int len = chalk.length;
//计算元素和
int sum = 0;
for (int i: chalk){
sum += i;
if (sum > k)//实时判断大小
break;
}
//计算循环次数
int c = k / sum;
k = k-c*sum;
for (int i=0;i<len;i++)
{
if (k<chalk[i])//要严格小于
return i;
else
k -= chalk[i];
}
return 0;
}
第三题
思路
没啥头绪,明天学习一下这类题的解法
—2021.6.13更新----
昨天做这个题除了暴力求解外,没有任何头绪,但是暴力求解又超时,只能放弃了。
今天看了一下大佬们的解法,发现使用前缀和+暴力java可以双100%
所以贴出来学习、记录一下。原文地址
算法步骤:
- 首先计算
行前缀和
、列前缀和
,方便后面直接调用,减少重复计算; - 获取
可能的最大尺寸
,然后开始暴力遍历
; - 对于每个可能满足条件的尺寸,从给定的矩阵左上角开始遍历(注意
边界范围
),如果此时圈定的幻方满足条件(每行、每列、两条对角线的值均相等),则直接返回此时的k值
,否在开始遍历下一个k值; - 因为k=1时绝对满足条件,所以
默认返回值为1
;
详细步骤详见代码注释。
代码
class Solution {
int[][] row;
int[][] col;
public int largestMagicSquare(int[][] grid) {
int r = grid.length;
int c = grid[0].length;
row = new int[r][c];
col = new int[r][c];
//首先计算前缀和,简化计算
//行前缀和
for (int i=0;i<r;i++)
{
row[i][0] = grid[i][0];
for (int j=1;j<c;j++)
{
row[i][j] = row[i][j-1] + grid[i][j];
}
}
//列前缀和
for (int j = 0; j < c; j++) {
col[0][j] = grid[0][j];
for (int i = 1; i < r; i++) {
col[i][j] = col[i-1][j] + grid[i][j];
}
}
//从可能的最大方形矩阵开始逐个暴力遍历,然后尺寸逐渐缩小
int n = Math.min(r,c);//因为数组可能不是正方形的,所以幻方的最大变成为数组边长的较小值
//从最大可能边长开始遍历,最小为2,因为长度为1时一定成立
for(int k=n;k>=2;k--)
{
for (int i=0;i<=r-k;i++)//注意边界范围,i最大为r-k,j最大为c-k
{
for (int j=0;j<=c-k;j++)
{
if (checkCount(i,j,k,grid))//如果每行、每列、两条对角线的值均相等,返回此时幻方的长度
return k;
}
}
}
return 1;//默认返回值,在合法输入下,1都满足条件
}
public boolean checkCount(int r, int c, int k, int[][] grid)
{
//检查行
//得到当前幻方第一行的和,以此为基准进行对比
int cur = row[r][c+k-1] - row[r][c] + grid[r][c];
for (int i=r+1;i<r+k;i++)
if (cur != (row[i][c+k-1] - row[i][c] + grid[i][c]))
return false;
//检查列
for (int j=c;j<c+k;j++)
if (cur != col[r+k-1][j] - col[r][j] + grid[r][j])
return false;
//检查对角线
int cur2 = 0;
//左上到右下
for (int i=r,j=c;i<r+k;i++,j++)
cur2 += grid[i][j];
if (cur2 != cur)
return false;
//左下到右上
cur2 = 0;
for (int i=r,j=c+k-1;i<r+k;i++,j--)
cur2 += grid[i][j];
return cur == cur2;
}
}
第四题
思路
没啥头绪,明天学习一下