0011 盛最多的水
思路:最初我们考虑由最外围两条线段构成的区域。现在,为了使面积最大化,我们需要考虑更长的两条线段之间的区域。如果我们试图将指向较长线段的指针向内侧移动,矩形区域的面积将受限于较短的线段而不会获得任何增加。但是,在同样的条件下,移动指向较短线段的指针尽管造成了矩形宽度的减小,但却可能会有助于面积的增大。因为移动较短线段的指针会得到一条相对较长的线段,这可以克服由宽度减小而引起的面积减小。
JAVA
package com.Manigoat;
public class Test0011盛最多的水 {
public static void main(String[] args) {
int height[]={1,8,6,2,5,4,8,3,7};
int answer=maxArea(height);
System.out.println(answer);
}
public static int maxArea(int[] height) {
int max = 0, l = 0, r = height.length - 1;
while (l < r) {
max = Math.max(max, Math.min(height[l], height[r]) * (r - l));
if (height[l] < height[r])
l++;
else
r--;
}
return max;
}
}
C++
int maxArea(vector<int>& height) {
int answer=0;
int l=0;
int r=height.size()-1;
while(l<r){
int temp= min(height[l],height[r])*(r-l);
answer=max(answer,temp);
if(height[l]<height[r]){
l++;
}else{
r--;
}
}
return answer;
}
0015 三数之和
题目:给你一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
**注意:**答案中不可以包含重复的三元组。
JAVA
package com.Manigoat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test0015三数之和 {
public static List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList();
int len = nums.length;
if(nums == null || len < 3) return ans;
Arrays.sort(nums); // 排序
for (int i = 0; i < len ; i++) {
if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
int L = i+1;
int R = len-1;
while(L < R){
int sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
while (L<R && nums[L] == nums[L+1]) L++; // 去重
while (L<R && nums[R] == nums[R-1]) R--; // 去重
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
}
}
C++
vector<vector<int>> threeSum(vector<int>& nums) {
int l1=0;
vector<vector<int>> res;
sort(nums.begin(), nums.end());
if(nums.size()<3)return res;
for(int i=0;i<nums.size()-2; i++){
if(i>0&&nums[i]==nums[i-1])continue;//去重
int l=i+1;
int r=nums.size()-1;
while(l<r){
int temp =nums[l]+nums[r]+nums[i];
if(temp==0){
res.push_back(vector<int>{nums[i],nums[l],nums[r]});
while(l<r&&nums[l+1]==nums[l]){
l++;
}
while(l<r&&nums[r-1]==nums[r]){
r--;
}
l++;
r--;
}else if(temp<0){
l++;
}else{
r--;
}
}
}
return res;
}
0016 最接近的三数之和
题目:给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
思路:与上题类似
JAVA
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int ans = nums[0] + nums[1] + nums[2];
for(int i=0;i<nums.length;i++) {
int start = i+1, end = nums.length - 1;
while(start < end) {
int sum = nums[start] + nums[end] + nums[i];
if(Math.abs(target - sum) < Math.abs(target - ans))
ans = sum;
if(sum > target)
end--;
else if(sum < target)
start++;
else
return ans;
}
}
return ans;
}
C++
int threeSumClosest(vector<int>& nums, int target) {
if(nums.size()<3){
return 0;
}
sort(nums.begin(), nums.end());
int size= nums.size();
int answer=nums[0]+nums[1]+nums[2];
for(int i=0;i<size;i++){
int l= i+1;
int r= size-1;
while(l<r){
int res= nums[i]+nums[l]+nums[r];
if(abs(answer-target)>abs(res-target)){
answer=res;
}
if(res<target){
l++;
}else if(res>target){
r--;
}else{
return answer;
}
}
}
return answer;
}
0018 四数之和
题目:给定一个包含 n 个整数的数组 nums
和一个目标值 target
,判断 nums
中是否存在四个元素 a,b,c*和 d ,使得 a + b + c + d 的值与 target
相等?找出所有满足条件且不重复的四元组。
思路:枚举前两个数i,j,然后剩下两个数使用双指针。
package com.Manigoat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test0018四数之和 {
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> ans = new ArrayList();
int len = nums.length;
if(nums == null || len < 4) return ans;
Arrays.sort(nums); // 排序
for (int k = 0; k <len-3 ; k++) {
/*去重*/
if(k>0&&nums[k]==nums[k-1]) {
continue;
}
/*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏*/
int min1=nums[k]+nums[k+1]+nums[k+2]+nums[k+3];
if(min1>target){
break;
}
/*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/
int max1=nums[k]+nums[len-1]+nums[len-2]+nums[len-3];
if(max1<target){
continue;
}
for (int i = k+1; i <len-2 ; i++) {
/*去重*/
if(i>k+1&&nums[i]==nums[i-1]) {
continue;
}
/*定义指针j指向i+1*/
int j=i+1;
/*定义指针h指向数组末尾*/
int h=len-1;
/*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏,忽略*/
int min=nums[k]+nums[i]+nums[j]+nums[j+1];
if(min>target){
continue;
}
/*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/
int max=nums[k]+nums[i]+nums[h]+nums[h-1];
if(max<target){
continue;
}
while(j<h){
int curr=nums[k]+nums[i]+nums[j]+nums[h];
if(curr==target){
ans.add(Arrays.asList(nums[k],nums[i],nums[j],nums[h]));
j++;
while(j<h&&nums[j]==nums[j-1]){
j++;
}
h--;
while(j<h&&i<h&&nums[h]==nums[h+1]){
h--;
}
}else if(curr>target){
h--;
}else {
j++;
}
}
}
}
return ans;
}
}
C++
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>>res;
if(nums.size()<4){
return res;
}
sort(nums.begin(),nums.end());
int size= nums.size();
for(int i=0;i<size-3;i++){
/*去重*/
if(i>0&&nums[i]==nums[i-1]) {
continue;
}
for(int j=i+1;j<size-2;j++){
int l=j+1;
int r=size-1;
/*去重*/
if(j>i+1&&nums[j]==nums[j-1]) {
continue;
}
while(l<r){
int sum=nums[i]+nums[j]+nums[l]+nums[r];
if(sum==target){
res.push_back(vector<int>{nums[i],nums[j],nums[l],nums[r]});
while(l<r&&nums[l]==nums[l+1]){
l++;
}
while(l<r&&nums[r]==nums[r-1]){
r--;
}
l++;
r--;
}else if(sum>target){
r--;
}else{
l++;
}
}
}
}
return res;
}
0026 删除排序数组中的重复项
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度.
JAVA
public int removeDuplicates(int[] nums) {
if (nums.length == 0) return 0;
int i = 0;
for (int j = 1; j < nums.length; j++) {
if (nums[j] != nums[i]) {
i++;
nums[i] = nums[j];
}
}
return i + 1;
}
C++
int removeDuplicates(vector<int>& nums) {
if (nums.size() < 2) return nums.size();
int j=0;
for(int i=0;i<nums.size();i++){
if(i>0&&nums[i]==nums[i-1]){
continue;
}
nums[j++]=nums[i];
}
return j;
}
0027 移除元素
给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。
JAVA
public int removeElement(int[] nums, int val) {
int i = 0;
for (int j = 0; j < nums.length; j++) {
if (nums[j] != val) {
nums[i] = nums[j];
i++;
}
}
return i;
}
C++
int removeElement(vector<int>& nums, int val) {
if(nums.size()<1){
return nums.size();
}
int j=0;
for(int i=0;i<nums.size();i++){
if(nums[i]==val){
continue;
}
nums[j++]=nums[i];
}
return j;
}
0283 移动零
**题目:**给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
**法一:**第一遍处理所有非零项,第二遍置零。
**法二:**我们使用两个指针i
和j
,只要nums[i]!=0
,我们就交换nums[i]
和nums[j]
public void moveZeroes(int[] nums) {
if(nums==null) {
return;
}
//第一次遍历的时候,j指针记录非0的个数,只要是非0的统统都赋给nums[j]
int j = 0;
for(int i=0;i<nums.length;++i) {
if(nums[i]!=0) {
nums[j++] = nums[i];
}
}
//非0元素统计完了,剩下的都是0了
//所以第二次遍历把末尾的元素都赋为0即可
for(int i=j;i<nums.length;++i) {
nums[i] = 0;
}
}
public void moveZeroes(int[] nums) {
if(nums==null) {
return;
}
//两个指针i和j
int j = 0;
for(int i=0;i<nums.length;i++) {
//当前元素!=0,就把其交换到左边,等于0的交换到右边
if(nums[i]!=0) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j++] = tmp;
}
}
}
0202 快乐数(黑科技:快慢指针)
**题目:**一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。
JAVA
public int getNext(int n) {
int totalSum = 0;
while (n > 0) {
int d = n % 10;
n = n / 10;
totalSum += d * d;
}
return totalSum;
}
public boolean isHappy(int n) {
int slowRunner = n;
int fastRunner = getNext(n);
while (fastRunner != 1 && slowRunner != fastRunner) {
slowRunner = getNext(slowRunner);
fastRunner = getNext(getNext(fastRunner));
}
return fastRunner == 1;
}
C++
int getNext(int n) {
int totalSum = 0;
while (n > 0) {
int d = n % 10;
n = n / 10;
totalSum += d * d;
}
return totalSum;
}
bool isHappy(int n) {
int slowRunner = n;
int fastRunner = getNext(n);
while (fastRunner != 1 && slowRunner != fastRunner) {
slowRunner = getNext(slowRunner);
fastRunner = getNext(getNext(fastRunner));
}
return fastRunner == 1;
}