力扣---数组专题I (简单)

题目名称

    • 1.867--转置矩阵--简单
    • 2.面试题 17.10. 主要元素
    • 3. 977-有序数组的平方
    • 4. 628-三个数的最大乘积
    • 5. 219-存在重复元素II
    • 6. 228-汇总区间
    • 7.1-两数之和
    • 8.167-两数之和II-输入有序数组

1.867–转置矩阵–简单

(1)题目条件:
力扣---数组专题I (简单)_第1张图片
(2)题解:

该题的目的是对已知矩阵进行转置,由于矩阵的行数和列数可能不相等,对于一个m行n列的矩阵,利用vector创建一个n行m列的空矩阵res,进行赋值操作,res[j][i] = matrix[i][j]。

class Solution {
public:
    vector<vector<int>> transpose(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        vector<vector<int>> res(n, vector<int>(m));
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                res[j][i] = matrix[i][j];
            }
        }
        return res;
    }
};

2.面试题 17.10. 主要元素

(1)题目条件:
力扣---数组专题I (简单)_第2张图片
(2)题解:

摩尔投票法:
在网上看到了一个形象的比喻,多个候选人要选举总统,如果其中一个人获得选票比其他人加起来的还多,那么即使进行一对一的比拼,最后剩下的还是这个人。

算法步骤:
I. 遍历数组元素,从第一个元素开始,计数器初始设置为0,st设置为数组第一个元素
II.遇到与st相同的元素时,count加1,否则,count减一。若count=0时,st更换为现在的元素
III.最后重新遍历一遍数组,看st的数量是否超过数组元素的一半,若超过一半,则返回该元素,否则返回-1.

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int n = nums.size();
        if(n == 0)  return -1;
        int st = nums[0], count = 0;
        for(int i = 0; i < n; i++){
            if(nums[i] == st){
                count++;
            }
            else{
                count--;
                if(count <= 0){
                    st = nums[i];
                    count = 1;
                }  
            }
        }
        count = 0;
        for(int i = 0; i < n; i++){
            if(st == nums[i])  count++;
        }
        if(count > n/2)  return st;
        else  return -1;
    }
};

排序方法:

将数组从小到大排序,若某个元素数量超过数组元素个数一半,数组最中间的元素一定是该元素。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int n = nums.size();
        if(n == 0)  return -1;
        sort(nums.begin(), nums.end());  //对数组从小到大排序
        int mid = nums[n/2];
        int count = 0;  //设置计数器
        for(int i = 0; i < n; i++){
            if(mid == nums[i])  count++;
        }
        if(count > n/2)  return mid;
        else  return -1;
    }
};

3. 977-有序数组的平方

(1)题目条件:
力扣---数组专题I (简单)_第3张图片
(2)解题方法:

暴力算法

先将数组元素都平方,然后将数组重新排序

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int n = nums.size();
        for(int i = 0; i < n; i++){
            nums[i] = nums[i] * nums[i];
        }
        sort(nums.begin(), nums.end());
        return nums;
    }
};

双指针

题目条件给出数组是非递减顺序排列的,对于正数来说,平方之后顺序不变,对于负数来说,平方之后顺序反转,所以平方后的最大值出现在数组开头或者结尾,最小值出现在数组中间。

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int n = nums.size()-1;
        int i, j;
        vector<int> ans(nums.size(), 0);
        for(i=0, j=nums.size()-1; i <= j;){
            if(nums[i]*nums[i] < nums[j]*nums[j]){
                ans[n--] = nums[j] * nums[j];
                j--;
            }
            else{
                ans[n--] = nums[i] * nums[i];
                i++;
            }
        }
        return ans;
    }
};

4. 628-三个数的最大乘积

(1)题目条件:
力扣---数组专题I (简单)_第4张图片
(2)题解:

最大值可能出现的情况只有两种,一种是三个全是正数,即数组最大的三个正数,另一种是两个负数一个正数,最小的两个负数和最大的一个正数

排序法

class Solution {
public:
    int maximumProduct(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int n = nums.size();
        return max(nums[0]*nums[1]*nums[n-1], nums[n-3]*nums[n-2]*nums[n-1]);
    }
};

非排序法

是要找到最大的三个值和最小的两个值就可以了

class Solution {
public:
    int maximumProduct(vector<int>& nums) {
        int n = nums.size();
        int max1 = -1000, max2 = -1000, max3 = -1000;  //第一、第二、第三大的数
        int min1 = 1000, min2 = 1000; //第一、第二小的数
        for(int i = 0; i < n; i++){
            if(nums[i] >= max1){  //大于最大的数
                max3 = max2; max2 = max1; max1 = nums[i]; 
            }
            else if(nums[i] >= max2){  //在max1和max2之间
                 max3 = max2; max2 = nums[i]; 
            }
            else if(nums[i] >= max3){   //在max2和max3之间
                max3 = nums[i];
            }
            if(nums[i] <= min1){  //比最小值还小
                min2 = min1; min1 = nums[i]; 
            }
            else if(nums[i] <= min2){  //在min1和min2之间
                min2 = nums[i];
            }
        }
        return max(min1*min2*max1, max3*max2*max1);
    }
};

5. 219-存在重复元素II

(1)题目条件:
力扣---数组专题I (简单)_第5张图片
(2)题解:

哈希表HashSet,HashSet继承于set类,set类的元素都是唯一的。
算法步骤:
i. 构造一个哈希表set,让哈希表的长度始终为k
ii. 遍历整个数组,看遍历的元素是否已经存在于set集合中了,若在集合中,则返回true,若没在集合中,则将该元素加入哈希表,若哈希表的长度超过k,则将最先加入的元素移除

解法说明:https://leetcode-cn.com/problems/contains-duplicate-ii/solution/hua-jie-suan-fa-219-cun-zai-zhong-fu-yuan-su-ii-by/

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        HashSet<Integer> set = new HashSet<>();
        for(int i = 0; i < nums.length; i++){
            if(set.contains(nums[i]))  return true;
            set.add(nums[i]);
            if(set.size() > k){
                set.remove(nums[i-k]);
            }
        }
        return false;
    }
}

6. 228-汇总区间

(1)题目条件:
力扣---数组专题I (简单)_第6张图片
力扣---数组专题I (简单)_第7张图片
(2)题解:

代码注意事项
i.while(i < n && nums[i-1]+1 == nums[i])要先写i(这个问题找了好久)
ii. c++中存在string类,将数字转换成字符可以使用to_string函数,在后面添加元素可以用append函数

class Solution {
public:
    vector<string> summaryRanges(vector<int>& nums) {
        int i = 0;
        vector<string> ret;
        int n = nums.size();
        while(i < n){
            int low = i;
            i++;
            while(i < n && nums[i-1]+1 == nums[i]){
                i++;
            }
            int high = i-1;
            string temp = to_string(nums[low]);
            if(low < high){  //证明存在一个区间
                temp.append("->");
                temp.append(to_string(nums[high]));
            }
            ret.push_back(temp);
        }
        return ret;
    }
};

7.1-两数之和

(1)题目条件:
力扣---数组专题I (简单)_第8张图片

(2)题解:

暴力枚举

class Solution {
public:
    vector twoSum(vector& nums, int target) {
        int n = nums.size();
        for(int i = 0; i < n; i++){
            int j = i+1;
            while(j < n){
                if(nums[i] + nums[j] == target){
                    return vector{i, j};
                }
                else{
                    j++;
                }
            }
        }
        return vector{-1,-1};
    }
};

哈希表

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map map = new HashMap<>();
        for(int i = 0; i < nums.length; i++){
            if(map.containsKey(target-nums[i])){
                return new int[]{map.get(target-nums[i]), i};
            }
            map.put(nums[i], i);
        }
        return new int[]{-1, -1};
    }
}

8.167-两数之和II-输入有序数组

(1)题目条件:
力扣---数组专题I (简单)_第9张图片

(2)题解:利用数组有序的条件

二分查找
固定第一个值,寻找第二个值的时候用二分查找的方法能缩短查找时间,提高效率。

class Solution {
public:
    vector twoSum(vector& numbers, int target) {
        int n = numbers.size();
        for(int i = 0; i < n; i++){
            int low = i+1, high = n-1;
            while(low <= high){
                int mid = (high-low)/2 + low;
                if(numbers[mid] == target - numbers[i]){
                    return {i+1, mid+1};
                }
                else if(numbers[mid] > target - numbers[i]){
                    high = mid - 1;
                }
                else{
                    low = mid + 1;
                }
            }
        }
        return {-1, -1};
    }
};

双指针
初始时将两个指针放在数组两侧,sum为两个指针指向数据之和
若sum==target,则找到唯一解
若sum 若sum>target,右指针向左移,减小sum

class Solution {
public:
    vector twoSum(vector& numbers, int target) {
        int low = 0, high = numbers.size()-1;
        while(low < high){
            int sum = numbers[low] + numbers[high];
            if(sum == target){
                return {low+1, high+1};
            }
            else if(sum > target){
                high--;
            }
            else{
                low++;
            }
        }
        return {-1,-1};
    }
};
```

你可能感兴趣的:(leetcode,数据结构)