1.数组(一)

https://leetcode-cn.com/tag/array/

题目汇总

1. 两数之和简单

4. 寻找两个有序数组的中位数困难

11. 盛最多水的容器中等

15. 三数之和中等

16. 最接近的三数之和中等

18. 四数之和中等

26. 删除排序数组中的重复项简单

27. 移除元素简单

31. 下一个排列中等

33. 搜索旋转排序数组中等

1. 两数之和简单

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。给定 nums = [2, 7, 11, 15], target = 9,返回 [0, 1]

思路一:暴力法,时间复杂度O(n*n),空间复杂度O(1)
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int length = nums.length;
        int[] result = new int[2];
        for(int i=0;i<length;i++){
            for(int j=i+1;j<length;j++){
                if(nums[i]+nums[j]==target)
                {
                    result[0] = i;
                    result[1] = j;
                }   
            }          
        }
        return result;
    }
}
思路二:哈希表,时间复杂度O(n),空间复杂度O(n)
import java.util.HashMap;
class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> map = new HashMap<>();
        int[] result = new int[2];
        for(int i=0; i< nums.length; i++){
            int other = target - nums[i];
            if(map.containsKey(other)){
                result[0] = map.get(other);
                result[1] = i;
            }
            map.put(nums[i], i);
        }
        return result;
    }
}

4. 寻找两个有序数组的中位数困难

给定两个大小为 m 和 n 的有序数组 nums1nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))
你可以假设 nums1nums2 不会同时为空。
nums1 = [1, 3],nums2 = [2],则中位数是 2.0

思路一:两个数组合并后排序,然后根据奇数偶数,返回中位数。

时间复杂度:遍历全部数组 O(m+n),不符合要求。

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int[] nums = new int[nums1.length+nums2.length];
        //两个数组合并
        for(int i=0;i<nums1.length;i++){
            nums[i] = nums1[i];
        }
        for(int j=0;j<nums2.length;j++){
            nums[nums1.length+j] = nums2[j];
        }
        //合并后的数组进行排序
        for(int i=0;i<nums.length-1;i++){
            for(int j=0;j<nums.length-1-i;j++){ 
                if(nums[j+1]<nums[j]){
                    int temp = nums[j+1];
                    nums[j+1] = nums[j];
                    nums[j] = temp;
                }
            }
        }
        
        if(nums.length%2 == 0){
            return (nums[nums.length/2]+nums[nums.length/2-1])/2.0;
        }
        else if(nums.length%2 == 1) {
            return nums[nums.length/2];
        }
        return 0.0;
    }
}
思路二:二分法

这个解法三太牛了,自己完全想不明白https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-2/

11. 盛最多水的容器中等

给你 n 个非负整数 a1a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。


图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

思路一:暴力法,时间复杂度O(n*n)
class Solution {
    public int maxArea(int[] height) {
        if (height == null || height.length == 0) {
            return 0;
        }
        int maxarea = 0;
        for(int i = 0; i<height.length; i++){
             for(int j = i + 1; j<height.length; j++){
                 maxarea = Math.max(maxarea, Math.min(height[i],height[j])*(j-i)) ;     
                 }             
             }
        return maxarea;
        } 
}
思路二:双指针,时间复杂度O(n)

移动指向较短线段的指针尽管造成了矩形宽度的减小,但却可能会有助于面积的增大。因为移动较短线段的指针会得到一条相对较长的线段,这可以克服由宽度减小而引起的面积减小。

class Solution {
    public int maxArea(int[] height) {
        int left = 0;
        int right = height.length-1;
        int maxArea = 0;
        while(left<right){
            maxArea = Math.max(maxArea,Math.min(height[left],height[right])*(right-left));
            if(height[left]<height[right])
                left++;          
            else 
                right--;          
        }
    return maxArea;
    }
}

15. 三数之和中等

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
给定数组 nums = [-1, 0, 1, 2, -1, -4],满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]

思路:排序+双指针,时间复杂度O(n*n)

参考https://leetcode-cn.com/problems/3sum/solution/pai-xu-shuang-zhi-zhen-zhu-xing-jie-shi-python3-by/
遍历排序后的数组:
若 nums[i]>0:后面不可能有三个数加和等于 0,直接返回结果;
对于重复元素:跳过,避免出现重复解;
令左指针 L=i+1,右指针 R=n-1,当 L<R 时,执行循环:
当 nums[i]+nums[L]+nums[R]==0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,R 移到下一位置,寻找新的解
若和大于 0,说明 nums[R]太大,R左移
若和小于 0,说明 nums[L]太小,L右移

class Solution {
     public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        if(nums == null||nums.length<3) 
            return res;
        for(int i = 0;i < nums.length;++i) {
            if(nums[i] > 0) 
                return res;
            if(i > 0 && nums[i] == nums[i-1])
                continue;
            int L = i+1;
            int R = nums.length-1;
            while (L < R) {
                int sum = nums[i] + nums[L] + nums[R];
                if(sum == 0) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[L]);
                    list.add(nums[R]);
                    res.add(list);
                    while(L < R && nums[L+1] == nums[L]) ++L;
                    while (L < R && nums[R-1] == nums[R]) --R;
                    ++L;
                    --R;
                } else if(sum > 0) {
                    --R;
                } else {
                    ++L;
                }
            }
        }
        return res;
    }   
}

16. 最接近的三数之和中等

给定一个包括 n个整数的数组 nums和 一个目标值 target。找出 nums中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. 因为(-1 + 2 + 1 = 2).

思路:排序+双指针,时间复杂度O(n*n)

和上道题目类似

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int len = nums.length;
        Arrays.sort(nums);
        int ans = nums[0] + nums[1] + nums[2];
        for(int i = 0; i<len; i++){
            int l = i + 1;
            int r = len - 1;
            while(l < r){
                int sum = nums[i]+nums[l]+nums[r];
                if(Math.abs(target - sum) < Math.abs(target - ans))
                    ans = sum;
                if(sum < target)
                    l++;
                else if(sum > target)
                    r--;
                else
                    return ans;
            }
        }
        return ans;
        
    }
}

18. 四数之和中等

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:答案中不可以包含重复的四元组。
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

思路:排序+双指针

和三数之和的思路一样,增加一层循环即可

class Solution {
    public 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 i = 0; i< len; i++){
            for(int j=i+1;j<len;j++){
                if(i>0&&nums[i]==nums[i-1]) continue;
                if(j>i+1&&nums[j]==nums[j-1]) continue;
                int l = j+1;
                int r = len-1;
                while(l<r){
                     int sum = nums[i]+nums[j]+nums[l]+nums[r];
                     if(sum==target){
                         ans.add(Arrays.asList(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 ans;
        
    }
}

26. 删除排序数组中的重复项简单

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,并在使用 O(1) 额外空间的条件下完成。
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 你不需要考虑数组中超出新长度后面的元素。

思路:双指针,时间复杂度:O(n)

用 2 个指针,一个i在前,一个j在后,比较 i 和 j 位置的元素是否相等。
如果相等,j 后移 1 位;如果不相等,将 j 位置的元素复制到 i+1 位置上,i 后移一位,j 后移 1 位。重复上述过程,直到 j 等于数组长度。
返回 i + 1,即为新数组长度。

class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums == null || nums.length == 0) 
            return 0;
        int i = 0;
        int j = 1;
        while(j < nums.length){
            if(nums[i] != nums[j]){
                if(j - i > 1){
                    nums[i + 1] = nums[j];
                }
                i++;
            }
            j++;
        }
    return i + 1;
    }
}

27. 移除元素简单

给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组**。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
给定 nums = [3,2,2,3], val = 3,函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。

思路:双指针,时间复杂度:O(n)

用 2 个指针,其中 i 是慢指针,j是快指针。当 nums[j]与给定的值相等时,递增 j 以跳过该元素。只要 nums[j]!=val,我们就复制 nums[j] 到 nums[i] 并同时递增两个索引。重复这一过程,直到 j 到达数组的末尾,该数组的新长度为 i。

class Solution {
    public int removeElement(int[] nums, int val) {
        if(nums == null || nums.length == 0) 
            return 0;
        int i = 0;
        int j = 0;
        while(j<nums.length){
            if(nums[j]!=val){
                nums[i]=nums[j];
                i++;
            }
            j++;
        }
    return i;
    }
}

官方题解 考虑了要删除的元素很少时的情况

31. 下一个排列中等

这是一道我看不懂题目的问题???
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,31,3,2
3,2,11,2,3
1,1,51,5,1

思路:

需要看题解https://leetcode-cn.com/problems/next-permutation/solution/xia-yi-ge-pai-lie-suan-fa-xiang-jie-si-lu-tui-dao-/
(1)从后向前查找第一个相邻升序的元素对 (i,j),满足 A[i] < A[j]。此时 [j,end) 必然是降序
(2)在 [j,end) 从后向前查找第一个满足 A[i] < A[k] 的 k。
(3)将 A[i] 与 A[k] 交换
(4)可以断定这时 [j,end) 必然是降序,逆置 [j,end),使其升序
(5)如果在步骤 1 找不到符合的相邻元素对,说明当前 [begin,end) 为一个降序顺序,则直接跳到步骤 4

class Solution {//执行用时:1 ms, 在所有 Java 提交中击败了99.71%的用户,//2020/08/03
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        int j = nums.length - 1;
        int k = nums.length - 1;
        while(i >= 0 && nums[i] >= nums[j]){//从后向前查找第一个相邻升序的元素对(i,j)
            i--;
            j--;
        }
        if(i >= 0){
            while(nums[i] >= nums[k]){//在 [j,end) 从后向前查找第一个满足 A[i] < A[k]的k
                k--;
            } 
            int temp = nums[i];
            nums[i] = nums[k];
            nums[k] = temp;//交换nums[i]、nums[k]的值
        }
       
        int left = j;
        int right = nums.length - 1;
        while(left < right){
            int temp = nums[left]; 
            nums[left] = nums[right]; 
            nums[right] = temp; 
            left++; 
            right--;//逆置 [j,end),使其升序
        }
    }
}

33. 搜索旋转排序数组中等

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
输入:nums = [4,5,6,7,0,1,2], target = 0,输出: 4

思路:

题目要找到一种O(log n)时间内的搜索方法,这提示我们可以用二分查找的方法。
分为两种情况进行讨论:
(1)4 5 6 7 0 1 2,此时nums[start]<=nums[mid],若nums[start]<=target<nums[mid],在前半部分进行查找
(2)5 6 7 0 1 2 4,此时nums[start]>nums[mid],若nums[mid]<target<=nums[end],在后半部分进行查找

class Solution {
    public int search(int[] nums, int target) {
        int start = 0;
        int end = nums.length - 1;
        
        while(start <= end){
            int mid = (end-start)/2+start;
            if(nums[mid]==target)
                return mid;
            if(nums[start]<=nums[mid]){//前半部分有序
                if(target>=nums[start]&&target<nums[mid]){//在前半部分查找
                    end = mid - 1;
                }
                else{
                    start = mid + 1;
                }      
            }
            else{//后半部分有序
                if(target>nums[mid]&&target<=nums[end]){//在后半部分查找
                    start = mid +1;
                }                
                else{
                    end = mid - 1;
                }
            }
        }
    return -1;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • 什么是数组? 数组简单来说就是将所有的数据排成一排存放在系统分配的一个内存块上,通过使用特定元素的索引作为数组的下...
    启明_b56f阅读 879评论 0 0
  • 线性表中的双指针法是指通过两个指针(游标)来指示线性表中的元素的方法。双指针的使用本身并没有什么神奇之处,但是通过...
    Like_eb56阅读 510评论 0 0
  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,320评论 0 2
  • 1. Remove Duplicates from Sorted Array Description: Easy ...
    BookThief阅读 595评论 0 1
  • 当我还是一个孩子的时候我就喜欢上了读书,除了用彩色铅笔在白色纸上乱画之外,我再找不到比阅读更有意思的事了。 ...
    蝴蝶飞走了吧阅读 222评论 1 0