数组

数组题:

  1. 数组移动,在原数组上操作。不需要额外的数组空间。性能 O(n).

1)       移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]

输出: [1,3,12,0,0]

说明:

必须在原数组上操作,不能拷贝额外的数组。

尽量减少操作次数。

 

解题思路:

定义一个移位索引,找到非零的元素按移位索引移位,并且把自己本来的位置设置为0。移位索引向后移位。

 

class Solution {

    public void moveZeroes(int[] nums) {

        int index = 0;

 

        for(int i = 0; i < nums.length; i++){

            if (nums[i] != 0) {              

                if(index < i) {

                    nums[index] = nums[i];

                    nums[i] = 0;

                }

                index++;

            }

        }

    }

}

 

 

2)       移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

 

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

 

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 

示例 1:

 

给定 nums = [3,2,2,3], val = 3,

 

函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。

 

你不需要考虑数组中超出新长度后面的元素。

示例 2:

 

给定 nums = [0,1,2,2,3,0,4,2], val = 2,

 

函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

 

注意这五个元素可为任意顺序。

 

你不需要考虑数组中超出新长度后面的元素。

 

解题思路:

定义移位索引,遍历数组。把非val的元素按移位索引设置。移位索引往后移。最后返回移位索引。

class Solution {

    public int removeElement(int[] nums, int val) {

        int index = 0;

        for(int i = 0; i < nums.length; i++){

            if(nums[i] != val){

                nums[index++] = nums[i];

            }

        }

        return index;

 

    }

}

 

3)       删除排序数组中的重复项
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

 

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例 1:

 

给定数组 nums = [1,1,2],

 

函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。

 

你不需要考虑数组中超出新长度后面的元素。

示例 2:

 

给定 nums = [0,0,1,1,1,2,2,3,3,4],

 

函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。

 

你不需要考虑数组中超出新长度后面的元素。

解题思路: 此题中元素是排好序的。定义一个移位索引用来存储移动的元素索引。 按元素比较来判断是否是重复元素。重复就往后找,不是重复就移位。把比较元素赋值为移位的元素。
class Solution {

    public int removeDuplicates(int[] nums) {

        if(nums.length <= 1){

            return nums.length;

        }

        int index = 0;

        int originalVal = nums[0];

 

        for(int i = 1; i < nums.length; i++){

            if(nums[i] != originalVal){

                index++;

                nums[index] = nums[i];

                originalVal = nums[i];

            }

        }

        return index+1;

    }

}

4)       删除排序数组中的重复项||
给定一个增序排列数组 nums ,你需要在 原地 删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。

 

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例 1:

输入:nums = [1,1,1,2,2,3]

输出:5, nums = [1,1,2,2,3]

解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 你不需要考虑数组中超出新长度后面的元素。

示例 2:

 

输入:nums = [0,0,1,1,1,1,2,3,3]

输出:7, nums = [0,0,1,1,2,3,3]

解释:函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。 你不需要考虑数组中超出新长度后面的元素。

 

解题思路:

跟上题增加一个重复次数。如果相等,单重复次数小于2的话正常移位。

class Solution {

    public int removeDuplicates(int[] nums) {

        if(nums.length <= 2){

            return nums.length;

        }

        int index = 0;

        int duplicate = 1;

        int original = nums[0];

 

        for(int i = 1; i < nums.length; i++){

            if(original == nums[i] && duplicate < 2){

                duplicate++;

                index++;

                nums[index] = nums[i];

            }

            if(original != nums[i]){             

                original = nums[i];

                duplicate = 1;

                index++;

                nums[index] = nums[i];

            }

        }

 

        return index + 1;

    }

}

 

  1. 数组查询排序

1)    颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

 

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

 

进阶:

 

你可以不使用代码库中的排序函数来解决这道题吗?

你能想出一个仅使用常数空间的一趟扫描算法吗?

 

 

示例 1:

 

输入:nums = [2,0,2,1,1,0]

输出:[0,0,1,1,2,2]

示例 2:

 

输入:nums = [2,0,1]

输出:[0,1,2]

示例 3:

 

输入:nums = [0]

输出:[0]

示例 4:

 

输入:nums = [1]

输出:[1]

 

解题思路:数组只有3种颜色, 把0往数组前端移,2往数组后端移。中间剩余的就是1。

 

class Solution {

    public void sortColors(int[] nums) {

        int length = nums.length;

        int redIndex = 0;

        int blueIndex = length - 1;

 

        for(int i = 0; i <= blueIndex; i++){

            if(nums[i] == 0){

                nums[redIndex++] = 0;

            } else if(nums[i] == 2){

                while(nums[blueIndex] == 2 && blueIndex > i){

                    blueIndex--;                  

                }             

                if(nums[blueIndex] == 0){

                    nums[redIndex++] = 0;

                }

                 nums[blueIndex] = 2;

                 blueIndex--;

            }

        }

 

        for(int k = redIndex; k <= blueIndex; k++){

            nums[k] = 1;

        }

    }

}

 

2). 数组中的第K个最大元素

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

 

示例 1:

 

输入: [3,2,1,5,6,4] 和 k = 2

输出: 5

示例 2:

 

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4

输出: 4

 

解题思路: 数组先进行排序,找出第k个元素。

 

class Solution {

    public int findKthLargest(int[] nums, int k) {

        Arrays.sort(nums);

        return nums[nums.length - k];

    }

}

 

3) 合并两个有序数组

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

 

说明:

 

初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。

你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

 

 

示例:

 

输入:

nums1 = [1,2,3,0,0,0], m = 3

nums2 = [2,5,6],       n = 3

 

输出:[1,2,2,3,5,6]

 

class Solution {

    public void merge(int[] nums1, int m, int[] nums2, int n) {

        int totalLength = m + n;

    

        while(m > 0 && n > 0) {

            if(nums2[n - 1] > nums1[m - 1]){

                nums1[totalLength - 1] = nums2[n-1];

                n--;

            } else{

                nums1[totalLength - 1] = nums1[m-1];

                m--;

            }

            totalLength--;

        }

 

        if(n > 0){

            for(int i = 0; i < n; i++){

                nums1[i] = nums2[i];

            }

        }   

}

}

 

  1.  双指针收缩
    1)两数之和

 

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。

 

函数应该返回这两个下标值 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) {

        int low = 0;

        int high = numbers.length - 1;

        int sum = 0;

        int [] result = new int[2];

 

        while(low < high){

            sum = numbers[low] + numbers[high];

            if(sum == target){

                result[0] = low + 1;

                result[1] = high + 1;

                return result;

            } else if(sum < target) {

                low++;

            } else {

                high--;

            }

        }

 

        return result;

    }

}

 

2) 验证回文串

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

 

说明:本题中,我们将空字符串定义为有效的回文串。

 

示例 1:

 

输入: "A man, a plan, a canal: Panama"

输出: true

示例 2:

 

输入: "race a car"

输出: false

 

解题思路:回文串就是左和右相同位置的字符相同。利用双指针夹击对撞

 

 

class Solution {

    public boolean isPalindrome(String s) {

        int first = 0;

        int last = s.length() - 1;

        char[] strArray = s.toCharArray();

 

        while(first < last){

            if(!Character.isLetterOrDigit(strArray[first])){

                first++;

                continue;

            }

            if(!Character.isLetterOrDigit(strArray[last])){

                last--;

                continue;

            }

 

            if(Character.toLowerCase(strArray[first]) != Character.toLowerCase(strArray[last])){

                return false;

            }

            first++;

            last--;

        }

        return true;

    }

}

 

3). 反转字符串中的元音字母

编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

示例 1

输入:"hello"
输出:"holle"

示例 2

输入:"leetcode"
输出:"leotcede"

解题思路:用双指针对碰,前后找元音字母。前后都找到后互换位置。

 

class Solution {

    private List<Character> vowels = Arrays.asList('a','e','i','o','u','A','E','I','O','U');

    public String reverseVowels(String s) {

        int first = 0;

        int last = s.length() - 1;

        char[] chars = s.toCharArray();

 

        while(first < last){

            if(!isVowel(chars[first])){

               first++;  

               continue;

            }

            

            if(!isVowel(chars[last])){

                last--;

                continue;

            }

  

            char temp = chars[first];

            chars[first] = chars[last];

            chars[last] = temp;

            first++;

            last--;

                      

        }

 

        return String.valueOf(chars);        

    }

 

    private boolean isVowel(char c){

        if(vowels.contains(c)){

            return true;

        } else{

            return false;

        }

    }

}

 

 

3). 盛最多水的容器

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

 

说明:你不能倾斜容器。

 

示例 1:

 

输入:[1,8,6,2,5,4,8,3,7]

输出:49

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

示例 2:

 

输入:height = [1,1]

输出:1

示例 3:

 

输入:height = [4,3,2,1,4]

输出:16

示例 4:

 

输入:height = [1,2,1]

输出:2

 

解题思路:使用双指针,前后夹击。我们会使用变量 maxarea 来持续存储到目前为止所获得的最大面积。 在每一步中,我们会找出指针所指向的两条线段形成的区域,更新 maxarea,并将指向较短线段的指针向较长线段那端移动一步。

 

class Solution {

    public int maxArea(int[] height) {

        int begin = 0;

        int end = height.length - 1;

        int oriBegin = height[0];

        int oriEnd = height[end];

        int maxVolume = 0;

 

        while (begin < end) {

            if(oriBegin > height[begin]){

                begin++;

                continue;

            }else {

                oriBegin = height[begin];

            }

 

            if(oriEnd > height[end]){

                end--;

                continue;

            } else{

                oriEnd = height[end];

            }

            maxVolume = Math.max(maxVolume, (end - begin) * (Math.min(height[begin], height[end])));

 

            if(height[begin] > height[end]){

                end--;

            }

            else{

                begin++;

            }

 

        }

        return maxVolume;

    }

}

 

4)       长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

 

示例:

 

输入:s = 7, nums = [2,3,1,2,4,3]

输出:2

解释:子数组 [4,3] 是该条件下的长度最小的子数组。

 

解题思路: 通过快慢双指针,快指针向前移动,判断组合是否大于目标值。小于目标值则继续往前移动。如果大于目标值了,就记下组合的长度。开始移动慢指针,如果大于目标值记下数组长度。如果小于目标值,则移动快指针。直到查找完毕。

class Solution {

    public int minSubArrayLen(int s, int[] nums) {

        if(nums.length == 0){

            return 0;

        }

        if(nums[0] >= s){

            return 1;

        }

        int begin = 0;

        int end = 1;

        int minLength = nums.length + 1;

        int sum = nums[begin];

 

        while(end < nums.length) {

            if(nums[end] >= s){

                return 1;

            }

            sum += nums[end];

            if(sum < s){

                end++;

            }

            else{

                minLength = Math.min(minLength, end - begin + 1);

                while((sum = sum - nums[begin++]) >= s){

                    minLength = Math.min(minLength, end - begin + 1);

                }

                end++;

            }

        }

        if(minLength == nums.length + 1){

            return 0;

        }

        return minLength;

    }

}

 

 

  1. 数组操作
    1) 寻找数组的中心索引

给定一个整数类型的数组 nums,请编写一个能够返回数组 “中心索引” 的方法。

 

我们是这样定义数组 中心索引 的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。

 

如果数组不存在中心索引,那么我们应该返回 -1。如果数组有多个中心索引,那么我们应该返回最靠近左边的那一个。

 

示例 1:

 

输入:

nums = [1, 7, 3, 6, 5, 6]

输出:3

解释:

索引 3 (nums[3] = 6) 的左侧数之和 (1 + 7 + 3 = 11),与右侧数之和 (5 + 6 = 11) 相等。

同时, 3 也是第一个符合要求的中心索引。

示例 2:

 

输入:

nums = [1, 2, 3]

输出:-1

解释:

数组中不存在满足此条件的中心索引。

 

解题思路:从题意可以得出中间分隔左右两边相等, 即leftSum + rightSum + num[i] = totalsum, leftsum = rightsum.

最后得出结果是 2 * leftsum = totalsum – nums[i]; i即为中间索引。

 

class Solution {

    public int pivotIndex(int[] nums) {

        if(nums.length <= 2){

            return -1;

        }

        int sum = 0;

        for(int num : nums) {

            sum += num;

        }

 

        int leftSum = 0;

 

        for(int i = 0; i < nums.length; i++) {

            if((leftSum << 1) == sum - nums[i]) {           

                return i;

            }

            leftSum += nums[i];

        }

 

        return -1;     

    }

}

 

 2) 搜索插入位置

 

本题使用二分查找法。

 

class Solution {

    public int searchInsert(int[] nums, int target) {

        int left = 0;

        int right = nums.length - 1;

 

        while(left < right) {

            int middle = left + ((right - left) >> 1);

            if(nums[middle] == target) {

                return middle;

            }

            else if(nums[middle] > target){

                right = middle - 1;

            } else {

                left = middle + 1;

            }

        }

 

        if(target > nums[left]){

            return left + 1;

        } else{

            return left;

        }

    }

}

 

3) 合并区间

给出一个区间的集合,请合并所有重叠的区间。

 

示例 1:

 

输入: intervals = [[1,3],[2,6],[8,10],[15,18]]

输出: [[1,6],[8,10],[15,18]]

解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

 

输入: intervals = [[1,4],[4,5]]

输出: [[1,5]]

解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。

 

解题思路:把二维数组进行升序排序,进行依次比较前一个的后坐标和后一个的前坐标,判断是否有交叉。没交叉直接放入合并列表,有交叉则直接修改列表中的后坐标。

 

class Solution {

    public int[][] merge(int[][] intervals) {

 

        Arrays.sort(intervals, Comparator.comparingInt((int[] num) -> num[0]));

        List<int[]> mergedList = new ArrayList<>();

 

        for(int i = 0; i < intervals.length; i++) {

            int low = intervals[i][0];

            int high = intervals[i][1];

 

            if(mergedList.size() == 0 || mergedList.get(mergedList.size() - 1)[1] < low){

                mergedList.add(intervals[i]);

            } else{

                mergedList.get(mergedList.size() - 1)[1] = Math.max(mergedList.get(mergedList.size() - 1)[1], high);

            }

        }

        return mergedList.toArray(new int[mergedList.size()][]);

    }

}

 

其他:

1. 数组拆分

给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。

返回该 最大总和 。

 

示例 1:

输入:nums = [1,4,3,2]
输出:4
解释:所有可能的分法(忽略元素顺序)为:
1. (1, 4), (2, 3) -> min(1, 4) + min(2, 3) = 1 + 2 = 3
2. (1, 3), (2, 4) -> min(1, 3) + min(2, 4) = 1 + 2 = 3
3. (1, 2), (3, 4) -> min(1, 2) + min(3, 4) = 1 + 3 = 4
所以最大总和为 4
示例 2:

输入:nums = [6,2,6,5,1,2]
输出:9
解释:最优的分法为 (2, 1), (2, 5), (6, 6). min(2, 1) + min(2, 5) + min(6, 6) = 1 + 2 + 6 = 9

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/array-and-string/c24he/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

解题思路:先排序,使配对的组合损失尽量减少。

 

class Solution {
    public int arrayPairSum(int[] nums) {
        Arrays.sort(nums);
        int sum = 0;

        for(int i = 0; i < nums.length; i = i + 2){
            sum += nums[i];
        }

        return sum;
    }
}
 
 

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

假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] 。

请找出其中最小的元素。

 

示例 1:

输入:nums = [3,4,5,1,2]
输出:1
示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0
示例 3:

输入:nums = [1]
输出:1

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/array-and-string/c3ki5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

解题思路:二分查找。

class Solution {
    public int findMin(int[] nums) {
        if(nums.length == 1) {
            return nums[0];
        }
        int low = 0;
        int high = nums.length - 1;

        while(low < high) {
            int mid = low + (high - low) / 2;
            if(nums[mid] > nums[high]) {
                low = mid + 1;
                continue;
            } else if(nums[mid] > nums[low]) {
                high = mid - 1;
                continue;
            } else if(nums[mid] < nums[low] && nums[mid] > nums[mid-1]){
                high = mid;
            } else{
                return nums[mid];
            }
        }
        return nums[low];
    }
}
 

3.两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。

 

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]

 

说明:

输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。
我们可以不考虑输出结果的顺序。
进阶:

如果给定的数组已经排好序呢?你将如何优化你的算法?
如果 nums1 的大小比 nums2 小很多,哪种方法更优?
如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table/xx5hsd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

方法一:使用HashMap来存储数组1中每个元素出现的次数。然后比较数组2。此方法适合,数组2很大,存储在磁盘上,不能一次加载到内存。

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        if(nums1.length > nums2.length) {
            intersect(nums2, nums1);
        }

         Map<Integer,Integer> numMap = new HashMap<>();
         for(int num : nums1) {
             int count = numMap.getOrDefault(num, 0) + 1;
             numMap.put(num, count);
         }
         
         int [] result = new int[nums1.length];
         int index = 0;
         for(int num : nums2) {
             if(numMap.get(num) == null) {
                 continue;
             }
             result[index++] = num;
             int count = numMap.get(num);
             if(count > 1) {
                 numMap.put(num, count - 1);
             } else{
                numMap.remove(num);
             }
         }
         return Arrays.copyOfRange(result, 0, index);
    }
}

 

方法2:数组排序好后,对数组元素依次一一比较。

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        int n1 = nums1.length;
        int n2 = nums2.length;

        if(n1 == 0 || n2 == 0){
            return new int[0];
        }
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int i = 0, j = 0;
        List<Integer> list = new ArrayList<>();
        while(i < n1 && j < n2){
            if(nums1[i] < nums2[j]){
                i++;
            }
            else if(nums1[i] > nums2[j]){
                j++;
            }
            else{
                list.add(nums1[i]);
                i++;
                j++;
            }
        }

        int[] result = new int[list.size()];

        for(int m = 0; m < list.size(); m++){
            result[m] = list.get(m);
        }

        return result;
    }
}
 
4. 滑动窗口的最大值

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:

滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
 

提示:

你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。

作者:Krahets
链接:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/58o46i/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解题思路:双指针依次往后遍历,暴力解法。其中可以发现有优化点,就是前一个比较过的组合,在下次比较时可以借用。如果弹出的数不是上次组合中的最大值,那么只要比较上个组合的最大值和新加入的数,取大者,可以大量减少重复比较。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length <= 1) {
            return nums;
        }
        
        int length = nums.length;
        int maxVal = nums[0];
        List<Integer> result = new ArrayList<Integer>();
        
        for(int i = 0; i <= length - k; i++) {
            if(i > 0 && nums[i-1] < maxVal) {
                 maxVal = Math.max(maxVal, nums[i+k-1]);
                 result.add(maxVal);
                 continue;
            }
            maxVal = nums[i];
            for(int j = i; j < i+k; j++) {
                maxVal = Math.max(maxVal, nums[j]);
            }
            result.add(maxVal);
        }
        
        int[] res = new int[result.size()];
        for(int i = 0; i < result.size(); i++) {
            res[i] = result.get(i);
        }
        return res;
    }
}
 
 

给定一个整数数组,编写一个函数,找出索引mn,只要将索引区间[m,n]的元素排好序,整个数组就是有序的。注意:n-m尽量最小,也就是说,找出符合条件的最短序列。函数返回值为[m,n],若不存在这样的mn(例如整个数组是有序的),请返回[-1,-1]

示例:

输入: [1,2,4,7,10,11,7,12,6,7,16,18,19]
输出: [3,9]

提示:

  • 0 <= len(array) <= 1000000
class Solution {
    public int[] subSort(int[] array) {
        if(array.length == 0) {
            return new int[] {-1, -1};
        }
        
        int maxVal = array[0];
        int minVal = array[array.length - 1];

        int m = -1, n = -1;

        for(int i = 0; i < array.length; i++) {
            if(array[i] >= maxVal) {
                maxVal = array[i];
            } 
            if(array[i] < maxVal) {
                n = i;
            }
        }

        for(int j = array.length - 1; j >= 0; j--) {
            if(array[j] <= minVal) {
                minVal = array[j];
            }
            if(array[j] > minVal) {
                m = j;
            }
        }

        return new int[] {m, n};

    }
}

 

31. 下一个排列

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须 原地 修改,只允许使用额外常数空间。

 

示例 1:

输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:

输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:

输入:nums = [1,1,5]
输出:[1,5,1]
示例 4:

输入:nums = [1]
输出:[1]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-permutation
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

class Solution {
    public void nextPermutation(int[] nums) {
        int len = nums.length;
        int i = len - 2;
        //从后往前找到第一个前面的数比后面的数小的数的位置
        while(i >= 0 && nums[i] >= nums[i+1]) {
            i--;
        }
        //如果找到,就从后往前找到第一个比上面的数大的数。
        if(i >= 0) {
            int j = len - 1;
            while(j >= 0 && nums[i] >= nums[j]) {
                j--;
            }
            //找到后进行交换
            swap(nums, i, j);
        }
        //对后面的数进行从小到大重排列,
        reverse(nums, i + 1, len-1); 
    }

    private void swap(int[] nums, int start, int end) {
        int temp = nums[start];
        nums[start] = nums[end];
        nums[end] = temp;
    }

    private void reverse(int[] nums, int begin, int end) {
        while(begin < end) {
            swap(nums, begin, end);
            begin++;
            end--;
        }
    }
}

 

posted @ 2020-12-19 15:11  闪闪的星光  阅读(186)  评论(0)    收藏  举报