LeetCode刷题之数组
1、(1)两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
//解法一、循环遍历,时间复杂度O(N²)
class Solution {
public int[] twoSum(int[] nums, int target) {
for(int i = 0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
if(nums[i]+nums[j]==target){
return new int[]{i,j};
}
}
}
return null;
}
}
//解法二 哈希表 时间复杂度O(N)
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map = new HashMap();
for(int i = 0;i<nums.length;i++){
if(map.get(target-nums[i])!=null){
return new int[]{i,map.get(target-nums[i])};
}else{
map.put(nums[i],i);
}
}
return null;
}
}
2、(11)盛水最多的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
//双指针 由于容纳的水量是由最短边决定的,如果不移动最短边,另一边怎么移动都不会超过当前容量。
class Solution {
public int maxArea(int[] height) {
int max = 0;
for(int i=0,j=height.length-1;i<j;){
int cur = (j-i)*Math.min(height[i],height[j]);
if(max<cur){
max = cur;
}
if(height[i]<height[j]){
i++;
}else{
j--;
}
}
return max;
}
}
3、(15)三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组
//先排序,内层用双指针,中间如果有重复的则跳过。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> list = new ArrayList();
if(nums.length<3)return list;
Arrays.sort(nums);
for(int i = 0;i<nums.length;i++){
if(i>0&&nums[i]==nums[i-1]){
continue;
}
for(int j = i+1,k = nums.length-1;j<k;){
if(j!=i+1&&nums[j]==nums[j-1]){
j++;
continue;
}
int sum = nums[i]+nums[j]+nums[k];
if(sum == 0){
List numlist = new ArrayList();
numlist.add(nums[i]);
numlist.add(nums[j]);
numlist.add(nums[k]);
list.add(numlist);
j++;
continue;
}
if(sum>0){
k--;
}else{
j++;
}
}
}
return list;
}
}
4、删除有序数组中的重复项
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
//快慢指针,慢指针指向上一个不重复的位
class Solution {
public int removeDuplicates(int[] nums) {
int flag = 0;
for(int i = 1;i<nums.length;i++){
if(nums[i]!=nums[flag]){
nums[++flag] = nums[i];
}
}
return flag+1;
}
}
5、下一个排列
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。
class Solution {
public void nextPermutation(int[] nums) {
if(nums.length<=1)return;
for(int i = nums.length-1;i>0;i--){
//找到比前一位大的数
if(nums[i]>nums[i-1]){
//将后续重排序,然后找最小的比i-1大的数,和i-1交换
Arrays.sort(nums,i,nums.length);
for(int j = i;j<nums.length;j++){
if(nums[j]>nums[i-1]){
int temp = nums[j];
nums[j] = nums[i-1];
nums[i-1] = temp;
return;
}
}
}
}
Arrays.sort(nums);
}
}
6、(33)搜索旋转排序数组
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
//二分法
class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
if(n==0){
return -1;
}
int high = n-1;
int low = 0;
int mid;
while(low<=high){
//((high-low)>>1)相当于(high-low)/2,取中值不能直接(low+high)/2,遇到负数会有问题。
mid = low+((high-low)>>1);
if(nums[mid]==target)return mid;
//判断前半有序还是后半有序,如果低位小于中值则前半有序,反之则后半有序
if(nums[low]<=nums[mid]){
if(nums[mid]>target&&nums[low]<=target){
high = mid-1;
}else{
low = mid+1;
}
}else{
if(nums[mid]<target&&nums[high]>=target){
low = mid + 1;
}else{
high = mid-1;
}
}
}
return -1;
}
}
7、(81)搜索旋转排序数组 II
已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转 ,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4] 。
给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false 。
class Solution {
public boolean search(int[] nums, int target) {
int n = nums.length;
if (n == 0) {
return false;
}
int high = n - 1;
int low = 0;
int mid;
while (low <= high) {
mid = low + ((high - low) >> 1);
if (nums[mid] == target) return true;
if (nums[low] == nums[mid] && nums[mid] == nums[high]) {
++low;
--high;
continue;
}
//判断前半有序还是后半有序
if (nums[low] <= nums[mid]) {
if (nums[mid] > target && nums[low] <= target) {
high = mid - 1;
} else {
low = mid + 1;
}
} else {
if (nums[mid] < target && nums[high] >= target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
}
return false;
}
}
8、(283)移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
//双指针
class Solution {
public void moveZeroes(int[] nums) {
int flag = 0;
for(int i = 0;i<nums.length;i++){
if(nums[i]!=0){
int temp = nums[flag];
nums[flag] = nums[i];
nums[i] = temp;
flag++;
}
}
}
}