分类 数组 下的文章

在排序数组中查找元素的第一个和最后一个位置

问题描述

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。

示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array

思路

emmmm,复杂度为O(n)

题解

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int n=nums.size();
        vector<int> ret;
        int min=-1;
        int max=-1;
        for(int i=0;i<n;i++){
            if(target==nums[i]){
                min=i;
                break;
            }
        }
        for(int i=0;i<n;i++){
            if(target==nums[i]){
                max=i;
            }
        }
        ret.push_back(min);
        ret.push_back(max);
        return ret;
    }
};

搜索旋转排序数组

问题描述

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

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array

思路

题目中要求算法时间复杂度必须是 O(log n) 级别->用二分查找。
题目中给出数组在某个点进行了旋转,数组在旋转之前是升序排列的,因此,最小的点即为旋转点。
找到了旋转点之后,将数组至多分为两个二分查找。
在两部分分别进行二分查找后,没找到目标值返回-1,如果找到返回坐标i,i一定大于-1.因此在两部分二分查找的结果中找最大值即可。

题解

class Solution {
public:
    int search(vector<int> &nums, int target) {
        int n = nums.size();
        if(n==0){
            return -1;
        }
        int min = nums[0];
        int flag = 0;
        for (int i = 1; i < n; i++) {
            if (min > nums[i]) {
                min = nums[i];
                flag = i;
            }
        }

        int location1 = refen(-1, nums, 0, flag - 1, target);
        int location2 = refen(-1, nums, flag, n - 1, target);
        return max(location1,location2);
    }

    int refen(int location, vector<int> &nums, int first, int last, int target) {
        int mid;
        while (first <= last && first >= 0 && last <= nums.size()) {
            mid = (first + last) / 2;
            if (target > nums[mid]) {
                first = mid + 1;
            } else if (target < nums[mid]) {
                last = mid - 1;
            } else {
                location = mid;
                break;
            }
        }
        return location;
    }
};

盛最多水的容器

问题描述

给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
question_11 (1).jpg
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例:
输入: [1,8,6,2,5,4,8,3,7]
输出: 49

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water

思路

容器容纳水的多少,取决于两个方面--两个直线间的距离以及两个直线中比较短的那个高度
本题的思想是双指针:
first=0;last=n-1;因为取决于比较短的那个高度,所以,每次短的那个指针向高的方向移动,来寻求高度的最大值。在这个过程中,直线之间的长度会变小,所以,这就需要在这个高度不断增大,长度不断较小的过程中寻求一个最大的值。

题解

class Solution {
public:
    int maxArea(vector<int>& height) {
        int n=height.size();
        int first=0;
        int last=n-1;
        int smax=0;
      
        while (first<last){
            int sa=min(height[first],height[last])*(last-first);
            if(s>smax){
                smax=s;
            }
            if(height[first]<height[last]){
                first++;
            }
            else if(height[first]>height[last])
            {
                last--;
            } else{
                first++;
            }
        }
        return smax;
    }
};

将字符串翻转到单调递增

问题描述:

如果一个由 '0' 和 '1' 组成的字符串,是以一些 '0'(可能没有 '0')后面跟着一些 '1'(也可能没有 '1')的形式组成的,那么该字符串是单调递增的。
我们给出一个由字符 '0' 和 '1' 组成的字符串 S,我们可以将任何 '0' 翻转为 '1' 或者将 '1' 翻转为 '0'。
返回使 S 单调递增的最小翻转次数。

示例 1:
输入:"00110"
输出:1
解释:我们翻转最后一位得到 00111.

示例 2:
输入:"010110"
输出:2
解释:我们翻转得到 011111,或者是 000111。

示例 3:
输入:"00011000"
输出:2
解释:我们翻转得到 00000000。
 
提示:
1 <= S.length <= 20000
S 中只包含字符 '0' 和 '1'

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/flip-string-to-monotone-increasing

思路:

还是太菜了...
最开始的时候试图从第一个非0的位置开始计算,如果后面的0多就将0变1,否则将1变0。
这种想法当然是错误的~
后来发现如果最后连续位置是1的话,根本没没必要算进来,于是做了一些改进,从第一个非0位置开始到最后一个0位置截至,判断0和1的个数,并相应做出转变。
emmmm,这么想也不对!emmmm,不出所料...
然后,评论区的大佬是这样子想的:

题解:

使数组唯一的最小增量

给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。

返回使 A 中的每个值都是唯一的最少操作次数。

示例 1:
输入:[1,2,2]
输出:1
解释:经过一次 move 操作,数组将变为 [1, 2, 3]。

示例 2:
输入:[3,2,1,2,1,7]
输出:6
解释:经过 6 次 move 操作,数组将变为 [3, 4, 1, 2, 5, 7]。
可以看出 5 次或 5 次以下的 move 操作是不能让数组的每个值唯一的。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-increment-to-make-array-unique

思路:

将数组排序,进行一系列的增量操作后,保证数组每个数都唯一,最后得到的结果一定是单调递增的。
具体操作:1、将数组排序。
2、第一次操作时A[i+1]一定大于等于A[i]。如果A[i+1]==A[i],将A[i+1]++,同时,记录所有增量的count++。
3、有了第一次操作后,A[i+1]可能<、>、或者=A[i]。如果等于,操作同上。如果>不用操作。如果<,A[i+1]=A[i]+1;count=count+A[i]+1-A[i+1]。
大概就是这样子!

题解:

class Solution {
public:
    int minIncrementForUnique(vector<int> &A) {
        int n=A.size();
        sort(A.begin(),A.end());
        int count=0;
        for(int i=0;i<n-1;i++){
            if(A[i]==A[i+1]){
                A[i+1]++;
                count++;
            } else if(A[i]>A[i+1]){
                count=count+A[i]+1-A[i+1];
                A[i+1]=A[i]+1;
            }
        }
        return count;
    }
};