往期:
JAVA 修炼秘籍第一章:《痛苦的折磨》
JAVA 修炼秘籍第二章:《逐渐魔化》
JAVA 修炼秘籍第三章:《绝地反击》
JAVA 修炼秘籍第四章:《闭关修炼》
JAVA 修炼秘籍第五章:《卧薪尝胆》
JAVA 修炼秘籍第六章:《鏖战》
前言: 最近一直在刷题,感觉没什么可写的博客,许久未更新大家也不会想我,毕竟没人看,哈哈哈哈哈,一个人的狂欢。
———————————————————生活以痛吻我,我却报之以歌。
题链接:来自力扣《两数相除》
给定两个数,一个除数与一个被除数。返回得到的商,要求不可以使用乘法(*),除法(\),mod(%)。
class Solution {
public int divide(int dividend, int divisor) {
//dividend =>除数。
//divisor =>被除数。
long sum=0;
//sum =>存储最后要返回的值
long x=dividend;
//其实这里的X与Y没有也可以,自我觉得会影响后续代码的清晰度
long y=divisor;
boolean bool=(x<0&&y>0)||(x>0&&y<0);
//bool =>查看两个数是否有负数存在,对结果进行正数与负数的调整。
if(x<0){
x=-x;//先将负数转为正数,方便后续计算
}
if(y<0){
y=-y;//先将负数转为正数,方便后续计算
}
//接下来采用二分查找,因为结果一定不会大于除数
//也就是结果会在0~X之间。
long left=0;//左指针
long right=x;//右指针
while(left<right){
//查找范围
long mid=left+right+1>>1;//中间值
if(Mul(mid,y)<=x){
//调用函数进行快速乘法
left=mid;
//相乘后返回结果小于等于X,左指针右移
}else{
right=mid-1;
//相乘后返回结果大于X,右指针左移
}
}
//将最终结果调整一下,判断是正数还是负数。
sum=bool?-left:left;
//判断是否溢出
if(sum<Integer.MIN_VALUE||sum>Integer.MAX_VALUE){
return Integer.MAX_VALUE;
}
//强制类型转换后返回
return (int)sum;
}
//快速相乘方法
public long Mul(long a,long b){
// a => 乘数
// b => 被乘数
// count => 积
long count=0;
while(b>0){
if((b&1)==1){
//按位与1,最后一位为1,积加等乘数。
count+=a;
}
// a+=a 等于 a=a*2;
a+=a;
// b>>=1 等于 b=b/2;
b>>=1;
}
return count;
}
}
所有的题解都写在了代码注释中,自己假设给定两个数值走一遍,就可以明白,主要就在于其中的二分法与快速乘法,两个基础算法。
题链接:来自力扣《反转矩阵后的得分》
给你一个二维矩阵(也就是二维数组),里面每个元素存放的不是1就是0,你可以选择任意一行元素或者一列元素进行修改,但是不可以单独选择一个元素进行修改。
修改规则为:假设选中了一行元素,那么这一行元素都要进行修改,将所有0改为1,1改为0。
在做出任意次数的移动后,将该矩阵的每一行都按照二进制数来解释,矩阵的得分就是这些数字的总和。
注意: 返回尽可能高的分数,也就是修改为总和为最高的矩阵
class Solution {
public int matrixScore(int[][] grid) {
int m=grid.length;//m为矩阵有几行
int n=grid[0].length;//n为矩阵有几列
int res=0;//矩阵修改后的得分
for(int i=0;i<m;i++){
//把每行第一个为0的行进行修改,此行为会让此行的二进制一定比修改前大
//比如:0111 => 7 修改后为 1000 => 8 所以修改第一位很关键
if(grid[i][0]==0){
for(int j=0;j<n;j++){
//此行全部反转,1-0=1,1-1=0;
//也可以写成 grid[i][j]^=1;
grid[i][j]=1-grid[i][j];
}
}
}
//现在进项每一列的检查
//这里检查后没有修改原数组而是直接计算了。
for(int j=0;j<n;j++){
int count=0;
//count保留每一列有几个1。
for(int i=0;i<m;i++){
count+=grid[i][j];
}
//如果此列中0比1多就进行反转,但是此处没有反转,而是直接取值了
//有点小偷鸡,也无伤大雅
//调用max方法,此行1的个数乘以当前位置的1在二进制中的十进制数字。
res+=Math.max(count,m-count)*(1<<(n-j-1));
}
return res;
}
}
力扣原题链接:点击进入。
牛客原题链接:点击进入。
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回值:返回滑动窗口中的最大值。
这道题会给出两个代码,一个是我在牛客上可以通过,而力扣无法通过的,另一个是两个网站都可以通过的。
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] nums, int k) {
//len保存数组长度,后续清晰度
int len=nums.length;
//max保留每个窗口最大值
int max=0;
//arr储存每个窗口最大值
ArrayList<Integer> arr=new ArrayList<Integer>();
//判断如果K==0直接结束
if(k==0){
return arr;
}
//循环遍历数组
for(int i=0;i<=len-k;i++){
//将max制空
max=0;
//查找当前窗口的最大值
for(int j=i;j<k+i;j++){
max=Math.max(max,nums[j]);
}
//储存每个窗口最大值
arr.add(max);
}
//返回
return arr;
}
}
这个方法非常简单,不需要过多的解释。
分块+预处理方法
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
//len储存输入数组长度
int len=nums.length;
//储存前缀最大值
int[] arr1=new int[len];
//储存后缀最大值
int[] arr2=new int[len];
//保留原数组中以i结尾的前缀最大值
for(int i=0;i<len;i++){
//如果i是k的倍数,那么nums[i]到nums[i+k-1]恰好是一个分组
if(i%k==0){
arr1[i]=nums[i];
}else{
arr1[i]=Math.max(arr1[i-1],nums[i]);
}
}
//保留原数组中以i开始的后缀最大值
for(int i=len-1;i>=0;i--){
if(i==len-1||(i+1)%k==0){
arr2[i]=nums[i];
}else{
arr2[i]=Math.max(arr2[i+1],nums[i]);
}
}
//arr1[i]和arr2[i+k-1]都等于分组中的最大值,
//因此无论窗口属于哪一种情况,都为答案
int[] arr=new int[len+1-k];
for(int i=0;i<=len-k;i++){
arr[i]=Math.max(arr1[i+k-1],arr2[i]);
}
return arr;
}
}
这里一般容易出错在后缀的最大值的位置,一定要看好判断条件,防止越界。
力扣原题链接:点击进入。
牛客原题链接:点击进入
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
class Solution {
public String minWindow(String s, String t) {
//储存t中每个元素出现的次数
int[] amp=new int[128];
for(int i=0;i<t.length();i++){
amp[t.charAt(i)]++;
}
//begin与end存储窗口的首位,
//d存储窗口的长度,
//count储存t中还有几个字符没被窗口包含
int count=t.length();
int len=s.length();
int end=0;
int head=0;
int d=Integer.MAX_VALUE;
int begin=0;
//循环遍历
while(end<len){
// amp[] > 0 说明该字符在t中出现,
//count-- 表示对应的字符被包含在了窗口,
//如果s中的字符没有在t中出现,
//则amp[]中对应的字符变为负值
if((amp[s.charAt(end++)]--) > 0){
count--;
}
//count为0了,这个时候证明窗口中已经完全包含了t中的所有元素
while(count==0){
if(end-begin<d){
d=end-begin;
head=begin;
}
// begin开始后移,继续向后寻找。
//如果begin后移后指向的字符在map中==0,表示是在T中出现的,如果没有出现,map[]中的值会是负值。
// 在T中的某个字符从窗口中移除,所以counter++。
if(amp[s.charAt(begin++)]++ == 0){
count++;
}
}
}
return d == Integer.MAX_VALUE ? "" : s.substring(head,head+d);
}
}