6.数组(六)

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

题目汇总

153. 寻找旋转排序数组中的最小值中等

154. 寻找旋转排序数组中的最小值 II困难

162. 寻找峰值中等

167. 两数之和 II - 输入有序数组简单

169. 多数元素简单,与剑指Offer一样

189. 旋转数组简单

209. 长度最小的子数组中等

216. 组合总和 III中等

217. 存在重复元素简单

153. 寻找旋转排序数组中的最小值中等,与剑指Offer一样

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请找出其中最小的元素。你可以假设数组中不存在重复元素
示例 1:
输入: [3,4,5,1,2],输出: 1
示例 2:
输入: [4,5,6,7,0,1,2],输出: 0

思路:二分查找

每次进入无序的那部分找出最小值

class Solution {
    public int findMin(int[] nums) {//执行用时 :0 ms
        if(nums == null || nums.length <= 0)
            return 0;
        int left = 0;
        int right = nums.length - 1;
        while(left < right){
            if(nums[left] < nums[right])
                return nums[left];
            int mid = (right - left) / 2 + left;
            if(nums[mid] > nums[right]){//从left到mid时递增的,最小值一定在mid到right之间
                left = mid + 1;
            }else if(nums[mid] < nums[right]){//从mid到right是递增的,最小值一定left到mid之间,包括mid
                right = mid;
            }else{//其他情况
                left++;
            }
        }
    return nums[left];
    }
}

154. 寻找旋转排序数组中的最小值 II困难

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请找出其中最小的元素。注意数组中可能存在重复的元素
示例 1:
输入: [1,3,5],输出: 1
示例 2:
输入: [2,2,2,0,1],输出: 0

思路:二分查找

与上题类似,区别在于数组中可能存在重复的元素,当nums[mid] = nums[right]时,应该将 right 减 1 防止重复数字是最小元素。

class Solution {
    public int findMin(int[] nums) {//执行用时 :0 ms
        int left = 0;
        int right = nums.length - 1;  
        while(left < right){
            if(nums[left] < nums[right])
                return nums[left];
            int mid = (right - left)/2 + left;
            if(nums[mid] > nums[right]){
                left = mid + 1;
            }else if(nums[mid] < nums[right]){
                right = mid;
            }else{
                right--;
            }
        }
    return nums[left];
    }
}

162. 寻找峰值中等

峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。
数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞
示例 1:
输入: nums = [1,2,3,1]
输出: 2
解释: 3 是峰值元素,你的函数应该返回其索引 2。
示例 2:
输入: nums = [1,2,1,3,5,6,4]
输出: 1 或 5
解释: 你的函数可以返回索引 1,其峰值元素为 2;或者返回索引 5, 其峰值元素为 6。
说明:你的解法应该是 O(logN)时间复杂度的。

思路一:

因为两个相邻的元素不相等,遍历数组,如果当前元素的值大于下一个元素的值,那么这个元素一定是峰值
如果元素递增,一直遍历到最后一个元素即为峰值。

class Solution {
    public int findPeakElement(int[] nums) {//执行用时 :0 ms
        for(int i=0;i<nums.length-1;i++){
            if(nums[i] > nums[i+1])
            return i;
        }
    return nums.length - 1;
    }
}
思路二:二分查找
class Solution {
    public int findPeakElement(int[] nums) {//执行用时 :0 ms
        if(nums == null || nums.length <= 0)
            return 0;
        int left = 0;
        int right = nums.length - 1;
        while(left < right){
            int mid = (right - left) / 2 + left;
            if(nums[mid] > nums[mid + 1]){// mid比右侧大, 峰顶在左侧或就在mid处
                right = mid;//[left,mid]
            }else{
                left = mid + 1;//mid比右侧小,峰顶在右侧[mid+1,right]
            }
        }
    return left;
    }
}

167. 两数之和 II - 输入有序数组简单

给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值index1 和 index2,其中 index1 必须小于 index2
说明:返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2

思路:双指针
class Solution {
    public int[] twoSum(int[] numbers, int target) {//执行用时 :1 ms
        int[] result = new int[2];
        if(numbers == null || numbers.length <= 1)
            return result;
        int left = 0;
        int right = numbers.length-1;
        while(left < right){
            int sum = numbers[left] + numbers[right];
            if(sum == target){
                result[0] = left + 1;//下标是从1开始的,要加1
                result[1] = right + 1;
                return result;
            }else if(sum < target){
                left++;
            }else{
                right--;
            }
        }
    return result;
    }
}

169. 多数元素简单,与剑指Offer一样

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2

思路:

数组中有一个数字出现的次数超过数组长度的一半,那么其他数字出现的次数总和一定比这个数字出现的次数要小。遍历数组的时候保存两个值,一个是数组中的一个数字,另一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1;不同则减一。如果次数为0,则保存下一个数字,并把次数设为1。遍历结束后,所保存的数字即为所求,然后再判断它是否符合条件。
时间复杂度为O(n)

class Solution {
    public int majorityElement(int[] nums) {//执行用时 :1 ms
        if(nums.length <= 0)
            return 0;
        int result = nums[0];
        int count = 1;//
        // 遍历每个元素,并记录次数;若与前一个元素相同,则次数加1,否则次数减1
        for(int i=1;i<nums.length;i++){
            if(nums[i]==result)
                count++;
            else{
                count--;
                if(count==0){
                    // 更新result的值为当前元素,并把次数设为1
                    result = nums[i];
                    count = 1;
                }
            }
        }
        // 判断result是否符合条件,即出现次数大于数组长度的一半
        int times = 1;
        for(int i=1;i<nums.length;i++){
            if(nums[i]==result){
                times++;
            }
        }
        if(times<=nums.length/2){
            return 0;
        }
     return result;   
    }
}

189. 旋转数组简单

给定一个数组,将数组中的元素向右移动 k个位置,其中 k是非负数。
示例 1:
输入: [1,2,3,4,5,6,7]k = 3
输出: [5,6,7,1,2,3,4]
解释:向右旋转 1 步: [7,1,2,3,4,5,6],向右旋转 2 步: [6,7,1,2,3,4,5], 向右旋转 3 步: [5,6,7,1,2,3,4]
示例 2:
输入: [-1,-100,3,99]k = 2
输出: [3,99,-1,-100]
解释: 向右旋转 1 步: [99,-1,-100,3],向右旋转 2 步: [3,99,-1,-100]
说明:尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。要求使用空间复杂度为 O(1) 的 原地算法。

思路一:使用额外的数组

定义一个新的数组,把原数组里下标为 i 的元素放在新数组 (i+k)%数组长度的位置,然后把新的数组拷贝到原数组中。
时间复杂度为 O(n),空间复杂度为O(n),不符合要求。

class Solution {
    public void rotate(int[] nums, int k) {//执行用时 :1 ms
        int[] a = new int[nums.length];
        for(int i=0;i<nums.length;i++){
            a[(i + k) % nums.length] = nums[i];
        }
        for(int i=0;i<nums.length;i++){
            nums[i] = a[i];
        }

    }
}
思路二:翻转

将数组中的元素向右移动 k个位置相当于将 k%n 个尾部元素移动到头部,剩下的元素依次向后移动。
分为三步进行,首先将所有元素反转,然后反转前 k 个元素,最后反转后面 n-k 个元素。
时间复杂度为 O(n),空间复杂度为O(1)。

class Solution {
    public void rotate(int[] nums, int k) {//执行用时 :0 ms
        k %= nums.length;
        reverse(nums, 0, nums.length-1);//首先将所有元素反转
        reverse(nums, 0, k-1);//然后反转前 k 个元素
        reverse(nums, k, nums.length-1);//再反转后面 n-k 个元素
    }
    private void reverse(int[] nums, int start, int end){
        while(start < end){
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start++;
            end--;
        }
    }
}

209. 长度最小的子数组中等

给定一个含有 n个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
进阶:如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法

思路:双指针

设置两个指针表示一个滑动窗口,窗口中的元素小于目标值,右指针向右移,扩大窗口。窗口中的元素大于目标值,比较当前窗口大小是否为最小值,左指针向右移,缩小窗口。

class Solution {
    public int minSubArrayLen(int s, int[] nums) {//执行用时 :2 ms
        if(nums == null || nums.length <= 0)
            return 0;
        int left = 0;
        int sum = 0;
        int min = Integer.MAX_VALUE;
        for(int right=0;right<nums.length;right++){
            sum += nums[right];//扩大区间
            while(sum >= s){
                min = Math.min(min, right - left + 1);
                sum -= nums[left++];//减小区间
            }
        }
    return min == Integer.MAX_VALUE ? 0 : min;
    }
}

216. 组合总和 III中等

找出所有相加之和为 nk个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:所有数字都是正整数。解集不能包含重复的组合。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]

39. 组合总和40. 组合总和 II类似

思路:回溯法+剪枝
class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {//执行用时 :0 ms
        List<List<Integer>> res = new ArrayList<>();
        dfs(1, n, k, new ArrayDeque<>(), res);
        return res;

    }
     /**
     * @param begin      本轮搜索的起点下标
     * @param n          和n
     * @param k          剩下要找 k 个数
     * @param path       从根结点到任意结点的路径
     * @param res        结果集变量
     */
    private void dfs(int begin,int n, int k,Deque<Integer> path,List<List<Integer>> res){
        if(k == 0 && n == 0){
            res.add(new ArrayList<>(path));
            return;
        }
        
        for(int i=begin;i<=9;i++){
            if( n-i < 0 || k <= 0)
                break;
            path.addLast(i);
            dfs(i+1, n-i,k-1,path,res);
            path.removeLast();
        }
    }
}

217. 存在重复元素简单,与剑指Offer一样

给定一个整数数组,判断是否存在重复元素。
如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false
示例 1:
输入: [1,2,3,1]
输出: true</pre>

思路:哈希

利用HashSet存储对象,从头到尾扫描数组中的每个数,如果哈希表里还没有这个数字,就把它加入哈希表;如果哈希表中已经存在该数字,就说明有重复的数字。时间复杂度O(n)

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

推荐阅读更多精彩内容