69 x的平方根
这题需要注意的点在于数据的数据范围导致计算x的平方可能会超过Integer范围
超出范围之后的大小判断就会出错
if(2147488281>2147395600)
System.out.println("yes");
//没有输出 注意不能这样,会超出Integer范围
解决:前面加个(long)就可以
第一思路是暴力遍历
for(int i=0;i<=x;i++){
if(i*i<=x&&(long)(i+1)*(i+1)>x) return i;//就可以
}
return 0;
最佳方案是二分法
class Solution {
public int mySqrt(int x) {
int left = 0;
int right = x;
while(left<=right){
int mid = (left+right)/2;
if((long)mid*mid==x) return mid;
else if((long)mid*mid<x) left = mid+1;
else right = mid-1;
}
return left-1;
}
}
27 移除元素
知道用快慢指针还是写了二十几分钟,还是因为代码思路不够清晰,fast和slow分开写,分开自增和赋值判断,弄得很乱。
其实只需要用slow来存去掉后的(判断fast指向的是不是val即可)
class Solution {
public int removeElement(int[] nums, int val) {
//58-20
int slow = 0;
for(int fast=0;fast<nums.length;fast++){
if(nums[fast]!=val){
nums[slow++] = nums[fast];
}
}
return slow;
}
}
26 删除数组的重复项
和上题是一样的,把判断的val换成数组中前一个元素即可
class Solution {
public int removeDuplicates(int[] nums) {
//32-36
int slow = 1;
for(int fast = 1;fast<nums.length;fast++){
if(nums[fast]!=nums[fast-1])
nums[slow++]=nums[fast];
}
return slow;
}
}
844 比较含退格的字符串
这题还是练习StringBuffer的用法
class Solution {
public boolean backspaceCompare(String s, String t) {
StringBuffer ss = new StringBuffer();
StringBuffer tt = new StringBuffer();
for(int i=0;i<s.length();i++){
if(s.charAt(i)!='#'){
ss.append(s.charAt(i));
// ss.append(Character.toString(s.charAt(i))); 不用将char转成String就可以直接append
}else if(ss.length()>0){
ss.deleteCharAt(ss.length()-1);//去掉末尾
}
}
for(int i=0;i<t.length();i++){
if(t.charAt(i)!='#'){
tt.append(Character.toString(t.charAt(i)));
}else if(tt.length()>0){//有可能多个退格
tt.deleteCharAt(tt.length()-1);//去掉末尾
}
}
//记得要先转成String才能用equals比较
return ss.toString().equals(tt.toString());
}
}
977 有序数组的平方
最简单的思路就是平方之后排序,排序需要O(nlogn)的时间复杂度和O(logn)的额外堆栈空间。
另一个思路是用双指针:
先找到第一个为正数的,两个指针往两边移动,比较平方谁大
class Solution {
public int[] sortedSquares(int[] nums) {
if(nums.length==1) return new int[]{nums[0]*nums[0]};//注意特殊判断,否则会数组越界
int[] res = new int[nums.length];
int i=0;
while(i<nums.length&&nums[i]<0) i++; //注意要前面的判断,否则会数组越界
//找到第一个正数
int right = i;
int left = i-1;
i=0;
while(left>=0&&right<nums.length){
if(nums[left]*nums[left]<nums[right]*nums[right]){
res[i++]=nums[left]*nums[left];
left--;
}else{
res[i++]=nums[right]*nums[right];
right++;
}
}
while(left>=0){
res[i++] = nums[left]*nums[left];
left--;
}
while(right<nums.length){
res[i++]=nums[right]*nums[right];
right++;
}
return res;
}
}
要注意边界判断,防止数组越界!!!!
看了题解还有一种更简洁的方式,也是用双指针,从两边往中间指,这样就不用边界判断!!
class Solution {
public int[] sortedSquares(int[] nums) {
//27-35
int left = 0;
int right = nums.length-1;
int[] res = new int[nums.length];
int i=nums.length-1;
//从两边往中间就需要从右边开始放,大的放
while(left<=right){
if(nums[left]*nums[left]>nums[right]*nums[right]){
res[i--] = nums[left]*nums[left];
left++;
}
else{
res[i--] = nums[right]*nums[right];
right--;
}
}
return res;
}
}
977 长度最小的子数组
就是数组的滑动窗口(或双指针)右边先移动,满足条件之后左边尝试移动,每次满足条件记录长度即可,时间复杂度O(N),空间复杂度O(1)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
//59
int left = 0;
int sublength = Integer.MAX_VALUE;
int num = 0;
for(int right=0;right<nums.length;right++){
num+=nums[right];
while(num>=target){
sublength=Math.min(sublength,right-left+1);
num-=nums[left++];
}
}
return sublength==Integer.MAX_VALUE?0:sublength;
}
}
904 水果成篮
需要把题目进行转义:找任意两个数连续最长的长度
还是可以用滑动数组(双指针),但是边界判断要注意,思路清晰但还是写了半个小时
class Solution {
public int totalFruit(int[] fruits) {
//00-31 任意两种类型的连续最长
int len = -2;
int left = 0;
int right = 0;
//特殊情况判断:只有一种类型
while(right<fruits.length&&fruits[right]==fruits[left]) right++;
if(right==fruits.length) return fruits.length;
//否则,将两种类型值存到a b
int a = fruits[left];
int b = fruits[right]; //存两种类型
while(right<fruits.length){
//在两种之内,right右移
if(fruits[right]==a||fruits[right]==b){
len = Math.max(right-left+1,len);
right++;
}else{
//此时right在第一次出现的第三个数字处
//left左移动
int tmp = right-1;//把tmp移到符合条件的最长的最右端点
while(tmp>=0&&fruits[tmp]==fruits[right-1]) tmp--;
left = tmp+1;//此时left和right指向的是更新后的新的两个类型
a = fruits[left];
b = fruits[right];
}
}
return len;
}
}
时间复杂度O(N),空间复杂度O(1)