原理:
LeetCode
283. 移动零
class Solution {
public void moveZeroes(int[] nums) {
int cur = 0;
int dest = -1;
while(cur < nums.length){
if(nums[cur] == 0){
cur++;
}else{
swap(nums,dest+1,cur);
dest++;
cur++;
}
}
}
public static void swap(int[] nums, int a, int b){
int tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
}
}
1089. 复写零![](https://img-blog.csdnimg.cn/direct/83e8d67f1c4f44c78170b5ed5fca7e80.jpeg)
第一次找复写cur的位置,但dest不满足循环时,cur多加了一次,所以要cur--;
但老师代码能直接在判断dest位置跳出循环 cur并不会多加
class Solution {
public void duplicateZeros(int[] arr) {
int cur = 0;
int dest = -1;
while(dest != arr.length - 1 && dest < arr.length){
if(arr[cur] != 0){
dest++;
}else{
dest += 2;
}
cur++;
}
cur--;
if(dest >= arr.length){
arr[arr.length-1] = 0;
cur--;
dest -= 2;
}
while(cur >= 0){
if(arr[cur] != 0){
arr[dest--] = arr[cur];
}else{
arr[dest--] = 0;
arr[dest--] = 0;
}
cur--;
}
}
}
202. 快乐数
当快慢指针相遇的时候(即相等的时候) ,如果都是1就是快乐数
当为1的时候也是一个环
鸽巢原理证明不存在int范围内一个数在无限次循环各位数加和后一直不重复
所以既然会出重复 slow走一步 fast走两步 一定会相遇(想象圆形操场,一个人速度1 一个人速度2,那么既然是环形,快的一定会和慢的相遇)
class Solution {
public boolean isHappy(int n) {
//定义快慢指针
int slow = n, fast = n;
if(slow == fast && slow == 1){
return true;
}
slow = fun(slow,1);
fast = fun(fast,2);
//slow走一步 fast走两步
while(fast != slow ){
slow = fun(slow,1);
fast = fun(fast,2);
}
//相遇(相等) 并且都为1
if(slow == 1){
return true;
}
return false;
}
public static int fun(int n, int k){
int ret = 0;
while(k-- != 0){
ret = 0;
while(n > 0){
int tmp = n % 10;
n /= 10;
ret += tmp*tmp;
}
n = ret;
}
return ret;
}
}
11. 盛最多水的容器
right和left下标的值,在向内枚举的时候,枚举的数字都是一样的,所以一端小的一定小于一端大大的
class Solution {
public int maxArea(int[] height) {
int left= 0, right = height.length-1;
int v = 0;
int h = 0,vMax = 0;
while(left < right){
//求体积
if(height[right] > height[left]){
h = height[left];
}else{
h = height[right];
}
v = (right - left)*h;
if(vMax < v){
vMax = v;
}
//指针移动
if(height[right] > height[left]){
left++;
}else{
right--;
}
}
return vMax;
}
}
611. 有效三角形的个数
right减减依据是left和right之间进行二元枚举,当right满足三角形时,那么right和其左边的大于left的值也都满足
left加加的依据是,left和right进行二元枚举,当left和right小的值也都不满足
然后从大到小固定最大的数
class Solution {
public int triangleNumber(int[] nums) {
//排序
sort(nums);
//定义双指针
int left = 0, right = nums.length-2, t = nums.length-1;
//累加所有三角形的和
int sum = 0;
int s1 = 0,s2 = 0;
while(t >= 2){
while(left < right){
if(nums[left]+nums[right] > nums[t]){
s1 = right-left;
right--;
}else{
left++;
}
s2 += s1;
s1 = 0;
}
t--;
right = t -1;
left = 0;
sum += s2;
s2 = 0;
}
return sum;
}
public static void sort(int[] nums){
for(int i = 0; i < nums.length; i++){
int tmp = nums[i];
int j = i-1;
for(; j>=0; j--){
if(nums[j] > tmp){
nums[j+1] = nums[j];
}else {
break;
}
}
nums[j+1] = tmp;
}
}
}
判断三角形,两边之和大于第三边,有比较大小就要想到排序
LCR 179. 查找总价格为目标值的两个商品
利用数组有序,当left一边小的时候,那么他和小于right的值加起来只会更小,同理right大的时候,和left右边再加起来只会更大
还有一种方法是二分查找
class Solution {
public int[] twoSum(int[] price, int target) {
int left = 0, right = price.length - 1;
int[] t = new int[2];
while(left < right){
if(price[left] + price[right] > target){
right--;
}else if(price[left] + price[right] < target){
left++;
}else{
t[0] = price[left];
t[1] = price[right];
break;
}
}
return t;
}
}
这里照顾编译器,在最后随便写了一个返回值
15. 三数之和
小优化是 固定的数是正数就可以跳出循环了,因为三个正数一定加和大于0
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> List = new ArrayList();
//排序
sort(nums);
if(nums[0] + nums[1] +nums[2] == 0&& nums.length == 3){
List<Integer> List1 = new ArrayList();
List1.add(nums[0]);
List1.add(nums[1]);
List1.add(nums[2]);
List.add(List1);
return List;
}else{
//遍历数组 //去重
for(int i = 0; i < nums.length-3; i++){
while(i>0&&nums[i] == nums[i-1] && i < nums.length-1 ){
i++;
}
int left = i+1;
int right = nums.length-1;
//变成求-a
int t = -nums[i];
while(left < right){
//找到一个 l r 后 去重 避免越界 l < r
if(nums[left] + nums[right] == t){
List<Integer> List1 = new ArrayList();
List1.add(nums[i]);
List1.add(nums[left]);
List1.add(nums[right]);
List.add(List1);
left++;
right--;
while(left < right && nums[left] == nums[left-1]){
left++;
}
while(left < right && nums[right] == nums[right+1]){
right--;
}
}else if(nums[left] + nums[right] > t){
right--;
}else{
left++;
}
}
}
return List;
}
}
public static void sort(int[] nums){
for(int i = 0; i < nums.length; i++){
int tmp = nums[i];
int j = i-1;
for(; j>=0; j--){
if(nums[j] > tmp){
nums[j+1] = nums[j];
}else {
break;
}
}
nums[j+1] = tmp;
}
}
}
i++放在了while(left < right)之后了,以前写for循环可能会因为i++的位置在for()中不知道怎么把中间的语句先执行,这个就是例子
18. 四数之和
在减的时候会溢出,变成long就好了
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
//定义List<List<Integer>>
List<List<Integer>> List = new ArrayList<>();
Arrays.sort(nums);
//固定a //去重
int len = nums.length;
for(int i = 0; i < len;){
//固定b //去重
for(int j = i+1; j < len; ){
int left = j+1;
int ringt = len - 1;
long targetN = (long)target -nums[i] - nums[j];
//双指针 //去重
while(left < ringt){
int sum = nums[left] + nums[ringt];
if(sum > targetN){
ringt--;
}else if(sum < targetN){
left++;
}else{
List.add(new ArrayList<Integer>(Arrays.asList(nums[i],nums[j],nums[left],nums[ringt])));
left++;
ringt--;
while(left < ringt && nums[left] == nums[left-1]){
left++;
}
while(left < ringt && nums[ringt] == nums[ringt+1]){
ringt--;
}
}
}
j++;
while(j < len && nums[j] == nums[j-1]){
j++;
}
}
i++;
while(i < len && nums[i] == nums[i-1]){
i++;
}
}
return List;
}
}