leetcode 初级算法--数组

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

26. 删除有序数组中的重复项

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k 。

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

示例 1:
输入:nums = [1,1,2]
输出:2, nums = [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]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
提示:

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 升序 排列
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        nums.erase(unique(nums.begin(),nums.end()), nums.end());
        return nums.size();
    }
};
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.empty()) return 0; // nums长度为0或1,不用处理直接返回
        if(nums.size() == 1) return 1;
        vector<int>::iterator slow = nums.begin(), fast = nums.begin()+1; // 双指针
        while(fast != nums.end()){ // 快指针找不同的数,找到一个就存到慢指针哪里,直到快指针找完整个数组
            if(*slow != *fast){
                *(++slow) = *fast;
            }
            ++fast;
        }
        if(slow != nums.end()-1) // 如果有重复的,就清除slow之后的
            nums.erase(slow+1, nums.end());
        return nums.size();
    }
};
66. 加一

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1:
输入:digits = [1,2,3]
输出:[1,2,4]
解释:输入数组表示数字 123。
示例 2:
输入:digits = [4,3,2,1]
输出:[4,3,2,2]
解释:输入数组表示数字 4321。
示例 3:
输入:digits = [0]
输出:[1]

提示:
  • 1 <= digits.length <= 100
  • 0 <= digits[i] <= 9
class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        // vector<int> d(digits);
        // 如果上一行去除注释并将下方digits 全部替换为d
        // 就不再改变digits了,但时间和空间占用都会大些
        int n = digits.size()-1;
        for(int i=n;i>=0;--i){ //从最后一位开始判断
           if(digits.at(i) == 9){ //如果是9
               digits[i] = 0; // 就把本位改为9,转到上一位
           }else{ 
               digits[i]++; // 否则本位加一
               return digits; // 并返回digits,结束
           }
        }
        digits.insert(digits.begin(),1); //如果循环到第一位了还是9,那就要最前面多加一位1
        return digits;
    }
};
122. 买卖股票的最佳时机 II

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润

示例 1:
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。
示例 3:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

提示:

  • 1 <= prices.length <= 3 * 104
  • 0 <= prices[i] <= 104
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size() == 1) return 0;
        int maxProfit = 0;
        vector<int>::iterator slow=prices.begin(), fast = prices.begin()+1;
        // 找各个不交叉子增区间的(最大值-最小值)之和
        while(fast != prices.end()){
                if(*fast > *slow){
                    while((fast != prices.end()-1) && (*(fast+1) > *fast)) ++fast;
                    maxProfit += *fast - *slow;
                    slow = fast+1;
                    if(slow == prices.end()) break;
                    fast += 2;
                } else {
                    ++slow;++fast;
                    if(slow == prices.end()) break;
                }
        }
        return maxProfit;
    }
};
class Solution {
public:
    int maxProfit(vector<int>& prices) {   
        int ans = 0;
        int n = prices.size();
        for (int i = 1; i < n; ++i) {
            ans += max(0, prices[i] - prices[i - 1]);
        }
        return ans;
    }
};
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/solution/mai-mai-gu-piao-de-zui-jia-shi-ji-ii-by-leetcode-s/
189. 轮转数组

给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 -1
  • 0 <= k <= 105
class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        if(nums.size() <= k) k %= nums.size();
        if(k == 0) return;
        int n = (nums.size()-k);
        // 把前面的复制插入到后面,再删除前面的
        nums.insert(nums.end(), nums.begin(), nums.begin()+n);
        nums.erase(nums.begin(), nums.begin()+n);
    }
};
class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        if(nums.size() <= k) k %= nums.size();
        if(k == 0) return;
        // 三次交换实现,类似反转32bit二进制数那道题
        reverse(nums.begin(), nums.end());
        reverse(nums.begin(), nums.begin()+k);
        reverse(nums.begin()+k, nums.end());
    }
};

注意,不要先复制后面的插入到开头再删除后面的,会出现一些问题

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k = k % n;
        int count = gcd(k, n);
        for (int start = 0; start < count; ++start) {
            int current = start;
            int prev = nums[start];
            do {
                int next = (current + k) % n;
                swap(nums[next], prev);
                current = next;
            } while (start != current);
        }
    }
};

// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/
217. 存在重复元素

给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。

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

提示:

  • 1 <= nums.length <= 105
  • -109 <= nums[i] <= 109
class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
    	// 排序,看是否有连续两个数相同的,也可以看find和rfind同一个数看是否相等
        sort(nums.begin(), nums.end());
        for(auto i=nums.begin()+1;i!=nums.end();++i){
            if(*(i-1) == *i) return true;
        }
        return false;
    }
};
class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
    	// set不存在重复元素,用nums初始化set,如果元素数少了,就是有重复元素
        set<int> se(nums.begin(), nums.end());
        return nums.size() != se.size();
    }
};
class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        unordered_set<int> us; // map也可以
        for(int x: nums){ // 逐个看是否已有,没有就存入,有了就返回true
            if(us.find(x) != us.end()) return true;
            us.insert(x);
        }
        return false;
    }
};
136. 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:
输入: [2,2,1] 输出: 1
示例 2:
输入: [4,1,2,1,2] 输出: 4

class Solution {
public:
    int singleNumber(vector<int>& nums) {
    // 排序,然后看第一第二个是否相等,第三第四是否相等....
    // 找出不等的一对,返回 前一个数
        sort(nums.begin(), nums.end());
        for(int i=1;i<nums.size();i+=2){
            if(nums.at(i) != nums.at(i-1)) return nums.at(i-1);
        }
        // 前面都是成对的,那就是最后一个
        return nums.back();
    }
};
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for (auto e: nums) ret ^= e;
        return ret;
    }
};
// 注: y^x^x == y 点赞
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/single-number/solution/zhi-chu-xian-yi-ci-de-shu-zi-by-leetcode-solution/
350. 两个数组的交集 II

给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int, int> m;
        vector<int> r;
        for(int i:nums1){
            if(m.find(i) != m.end()){
                ++m[i];
            } else {
                m[i] = 1;
            }
        }
        for(int j:nums2){
            if(m.find(j) != m.end() && m[j]>0){
                r.push_back(j);
                m[j]--;
            }
        }
        return r;
    }
};

进阶:

如果给定的数组已经排好序呢?你将如何优化你的算法?
可以两个指针分别指向两个数组的开头,那个对应的数小,那个指针就向后移动一次,如果相等就将数字加到要返回的数组中并且两个指针都向后移动。直到某个指针到达数组末尾。
如果 nums1 的大小比 nums2 小,哪种方法更优?
如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        if (nums1.size() > nums2.size()) {
            return intersect(nums2, nums1);
        }
        unordered_map <int, int> m;
        for (int num : nums1) {
            ++m[num];
        }
        vector<int> intersection;
        for (int num : nums2) {
            if (m.count(num)) {
                intersection.push_back(num);
                --m[num];
                if (m[num] == 0) {
                    m.erase(num);
                }
            }
        }
        return intersection;
    }
};

// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/intersection-of-two-arrays-ii/solution/liang-ge-shu-zu-de-jiao-ji-ii-by-leetcode-solution/
283.移动零

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

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

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

提示:

  • 1 <= nums.length <= 104
  • -231 <= nums[i] <= 231 - 1

进阶:你能尽量减少完成的操作次数吗?

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
    // 遇0则删,并记录0的个数,最后在数组最后补上0
        int n = 0;
        auto it=nums.begin();
        while(it!=nums.end()){
            if(*it){
                ++it;
            } else {
                it = nums.erase(it);
                ++n;
            }
        }
        nums.insert(nums.end(),n,0);
    }
};
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
    // 两个指针,快指针遍历整个数组,快指针非零就和慢指针交换且慢指针向后移动,以此来将非零数聚集到前面
        int n = nums.size(), left = 0, right = 0;
        while (right < n) {
            if (nums[right]) {
                swap(nums[left], nums[right]);
                left++;
            }
            right++;
        }
    }
};
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/move-zeroes/solution/yi-dong-ling-by-leetcode-solution/
1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

提示:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map <int, int> m;
        int n=nums.size();
        for(int i=0;i<n;++i){
            if(m.count(target-nums[i])){
                return {m[target-nums[i]],i};
            }
            m[nums[i]]=i;
        }
        return {};
    }
};
36. 有效的数独

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

  • 数字 1-9 在每一行只能出现一次。
  • 数字 1-9 在每一列只能出现一次。
  • 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 空白格用 ‘.’ 表示。

示例 1:
输入:board =
[[“5”,“3”,“.”,“.”,“7”,“.”,“.”,“.”,“.”]
,[“6”,“.”,“.”,“1”,“9”,“5”,“.”,“.”,“.”]
,[“.”,“9”,“8”,“.”,“.”,“.”,“.”,“6”,“.”]
,[“8”,“.”,“.”,“.”,“6”,“.”,“.”,“.”,“3”]
,[“4”,“.”,“.”,“8”,“.”,“3”,“.”,“.”,“1”]
,[“7”,“.”,“.”,“.”,“2”,“.”,“.”,“.”,“6”]
,[“.”,“6”,“.”,“.”,“.”,“.”,“2”,“8”,“.”]
,[“.”,“.”,“.”,“4”,“1”,“9”,“.”,“.”,“5”]
,[“.”,“.”,“.”,“.”,“8”,“.”,“.”,“7”,“9”]]
输出:true
示例 2:
输入:board =
[[“8”,“3”,“.”,“.”,“7”,“.”,“.”,“.”,“.”]
,[“6”,“.”,“.”,“1”,“9”,“5”,“.”,“.”,“.”]
,[“.”,“9”,“8”,“.”,“.”,“.”,“.”,“6”,“.”]
,[“8”,“.”,“.”,“.”,“6”,“.”,“.”,“.”,“3”]
,[“4”,“.”,“.”,“8”,“.”,“3”,“.”,“.”,“1”]
,[“7”,“.”,“.”,“.”,“2”,“.”,“.”,“.”,“6”]
,[“.”,“6”,“.”,“.”,“.”,“.”,“2”,“8”,“.”]
,[“.”,“.”,“.”,“4”,“1”,“9”,“.”,“.”,“5”]
,[“.”,“.”,“.”,“.”,“8”,“.”,“.”,“7”,“9”]]
输出:false
解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

提示:

  • board.length == 9
  • board[i].length == 9
  • board[i][j] 是一位数字(1-9)或者 ‘.’
class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        bool che[3][9][9]{false}; // bool省空间,存九行、九列、九块的1-9是否已经出现过了
        for(int i=0;i<9;++i){
            for(int j=0;j<9;++j){
                char ch = board[i][j];
                if(ch != '.'){
                    int c = ch-'1';
                    int bn = i/3+(j/3)*3;
                    if(che[0][i][c] || che[1][j][c] || che[2][bn][c]) return false; // 如果第二次出现就false
                    che[0][i][c] = true;
                    che[1][j][c] = true;
                    che[2][bn][c] = true;
                }
            }
        }
        return true;
    }
};
48. 旋转图像

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:
输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
    // 四次一循环,除去中间可能有一个不变,其余均为四个数依次更换位置,三次交换两个数就可以做到
        int n = matrix.size();
        int im = n/2;
        // 对上方1/4进行处理就可以
        for(int i=0;i<im;++i){
            int jm = n-i*2-1;
            for(int j=0;j<jm;++j){
                swap(matrix[i][j+i],matrix[i+j][i+jm]);
                swap(matrix[i][j+i],matrix[i+jm-j][i]);
                swap(matrix[i+jm-j][i],matrix[i+jm][i+jm-j]);
            }
        }
    }
};

官方题解链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今夕何夕2112

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值