0804
移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
首先简单写一下我的思路,这道题目需要的是删除不存在的元素,其实也就是在原来的基础上将不需要的数据移动到数组的后面然后返回你需要的长度就行!
那么就可以使用双指针方式进行,走到对应的数据的位置的时候可以进行数据的交换,然后当两个指针碰撞的时候就可以结束了!
class Solution {
public int removeElement(int[] nums, int val) {
int length=nums.length;
if(length==0){
return 0;
}
int index=length-1;
//采用双指针的方式
for(int i=0;i<length;i++){
int prex=nums[i];
int last=nums[index];
if(prex==val){
nums[i]=nums[index];
i--;
index--;
}
if(i==index){
break;
}
}
return index+1;
}
}
0805
POW函数
实现 pow(x, n) ,即计算
x
的整数n
次幂函数(即,xn
)。
方法一:暴力求解
首先面对这个问题,我自己最开始的想法当然还是使用暴力破解,因为这里暴力破解很方便嘛,但是就会遇到一个问题,那就是我的提交超出了时间限制,也就是说明我的时间复杂度太大的。
下面是我使用暴力求解的代码:
class Solution {
public double myPow(double x, int n) {
if(n==0) return 1;
//这里最简单的当然是使用for循环
double num=1.0;
if(n>0){
for(int i=1;i<=n;i++){
num*=x;
}
}
if(n<0){
for(int i=1;i<=-n;i++){
num/=x;
}
}
return num;
}
}
方法二:快速幂+递归
然后我们还有第二种方法,那就是使用快速幂+递归的方式
我们首先举几个例子做一下说明:
我们算x^64的时候,我们是不是可以这样算:
x^2 -> x^4 ->x^8 -> x^16 -> x^32 -> x^64
也就是在原来的基础上每次乘以2
class Solution{
public double myPow(double x, int n) {
long N = n;
return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
}
public double quickMul(double x, long N) {
if (N == 0) { //最后都会到达这里,然后相当于从下往上进行计算
return 1.0;
}
double y = quickMul(x, N / 2);
return N % 2 == 0 ? y * y : y * y * x;
}
}
这题有一点没有说清楚那就是边界,没有指明我的n的取值的范围,假设我的N取值为无限大,那么就会造成溢出,所以面试的时候如果遇到这个题目就需要问清楚啦!😉🎆🎊
0806
旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
方法一:原地旋转
那么首先我们拿到这个题目相比大家都知道了,我们要做的就是找规律!!
这个时候如果我们直接将元素进行移动,那么就一定会出现一个问题,那就是我们原来在(col,n-row-1)位置上的元素会被覆盖,这个时候我们就需要使用一个临时变量temp去存储这个位置上的元素。
那么在(col,n-row-1)上的元素又会移动到哪里?
根据上面规律我们可以代入得,会移动到(n-row-1,n-col-1)
然后我们再来一次,会发现在(n-row-1,n-col-1)位置上的元素会移动到(n-col-1,row)
最后我们再来最后一次,会发现(n-col-1,row)得元素就会变到(row,col)的位置上,发现了什么?我们又转回来了!!!
所以,最后我们可以得到一个方程式,就是
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < (n + 1) / 2; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[n - j - 1][i];
matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
matrix[j][n - i - 1] = temp;
}
}
}
}
方法二:两次翻转
首先我们来一个概念的理解,那就是关于图片的翻转的
好了,有了上面的规律,我们就可以用这种翻转来解决我们的问题了!
对于旋转九十度,得到的为 (row=col , col=n-row-1)
用我们图片翻转的规律就是 : 水平翻转+反对角线翻转
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
// 水平翻转
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < n; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[n - i - 1][j];
matrix[n - i - 1][j] = temp;
}
}
// 主对角线翻转
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
}
}
好了,然后我们再来几个翻转的案例,如果我们旋转180°,相当于怎么翻转??
1. 旋转180°之后我们的结果就是(row=n-row-1 col=n-col-1)
那么是怎么翻转过来的?
那就相当于先水平翻转再垂直翻转!
2. 旋转270°之后的结果就是 (row=n-col-1 col=row)
旋转就相当于先垂直翻转再主对角翻转!
0807
最后一个单词的长度
给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。
单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
class Solution {
public int lengthOfLastWord(String s) {
//可以使用判断的方式,就是说从后往前,使用指针的方式,如果当前的值不是空就开始计数,如果当前的值为空就继续往前找直到
//遇到非空
int len=s.length()-1;
while(s.charAt(len)==' '){ //这里不可使用if,因为如果你使用if的话如果后面有两个空字符的话就不能完全排除了!
len--;
}
int maxChuan=0;
while(len>=0 && s.charAt(len)!=' '){
maxChuan++;
len--;
}
return maxChuan;
}
}
两数相除
给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。
这里有个很恶心的点就是要考虑溢出的情况
那么大家可以想到的都是使用加法或者减法来进行,但是这就有个不好的地方就是时间复杂度比较高,比如我写的,就因为时间复杂度太大而超出了时间限制
class Solution {
public int divide(int dividend, int divisor) {
//可以使用while循环进行计算
//题目只是要求我们不使用乘法、除法和求模运算
//那么在这里我们可以使用加法
//while(num<=dividend)的时候就继续加上divisior,然后使用一个变量计算,最后返回这个变量就行
// if(dividend==Integer.MIN_VALUE && divisor=-1) return Integer.MAX_VALUE;
if(dividend == 0) return 0;
if(dividend == Integer.MIN_VALUE && divisor == -1) return Integer.MAX_VALUE;
int sum=0;
int count=-1;
if(divisor<0 && dividend >0){
int divisor1=0;
divisor1=-divisor;
while(sum<=dividend){
sum+=divisor1;
count++;
}
return -count;
}
else if(dividend<0 && divisor >0 ){
int diviend1=0;
diviend1=-dividend;
while(sum<=diviend1){
sum+=divisor;
count++;
}
return -count;
}
else if(dividend<0 && divisor<0){
int divisor1=0;
int diviend1=0;
diviend1=-dividend;
divisor1=-divisor;
while(sum<=diviend1){
sum+=divisor1;
count++;
}
return count;
}
else{
while(sum<=dividend){
sum+=divisor;
count++;
}
return count;
}
}
}
然后看了一位大神的讲解,发现还可以使用其他的方式进行,就是使用递归的方式
链接如下:Java 代码简洁 思路清晰 - 两数相除 - 力扣(LeetCode)
这位大神的思想就是使用递归的方式进行,第一次加上n 第二次加上2n 以此类推
因为这里的题目有要求,就是说我们要考虑溢出的情况
那么我们在代码中首先把这几个需要考虑的情况考虑全面:
①当被除数等于0的时候,返回0
if(dividend==0) return 0;
②当出现溢出的时候,也就是我们被除数为负数的最边上的数据同时除数为1的时候,因为正数没有对应的,我们统一返回正数的最大数
if(dividend==Integer.MIN_VALUE&&divisor==1) return Integer.MAX_VALUE;
然后因为负数的范围大于正数,所以我们开始全部用负数作为计算
然后我们的代码如下所示:
class Solution {
public int divide(int dividend, int divisor) {
if(dividend==0) return 0;
if(dividend==Integer.MIN_VALUE && divisor==1) return Integer.MAX_VALUE;
int flag=1; //我们的符号
if(dividend<0 && divisor>0 || dividend>0 && divisor<0)
flag=-1;
//我们需要将数据全部取为负数
dividend=dividend>0 ? -dividend:dividend;
divisor=divisor>0 ? -divisor:divosor;
return flag*helper(dividend,divisor);
}
//我们需要创造一个函数去实现我们需要的功能
public int helper(int a,int b){
if(a>=b)
return a>b ?0:1;
int tp=b;
int res=0;
int count=1;
while(a<b && tp<0){
a-=b;
res+=count;
tp+=tp;
count+=count;
}
return res+helper(a,b)
}
}