【数据结构】数组

数组的定义

数组是存放在连续内存空间上的相同类型数据的集合。
数组的元素是不能删的,只能覆盖。

区间的定义就是不变量,在循环中坚持根据查找区间的定义来做边界处理,就是循环不变量规则。

leetcode704.二分查找

二分查找的前提:数组是有序的,且数组中无重复元素。
二分法里区间的定义一般有两种:

  • 左闭右闭,即[left, right]
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right) {	// 当left==right,区间[left,right]依然有效
            int middle = left + ((right - left) / 2);	// 防止溢出,等同于(left+right)/2
            if(nums[middle] > target) {
                right = middle - 1;		// 新区间[left, middle-1]
            }
            else if (nums[middle] < target) {
                left = middle + 1;		// 新区间[middle+1, right]
            }
            else {
                return middle;
            }
        }
        return -1;
    }
};
  • 左闭右开,即[left, right)
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size();
        while(left < right) {	// 当left==right,区间[left,right)无效
            int middle = left + ((right - left) / 2);	// 防止溢出,等同于(left+right)/2
            if(nums[middle] > target) {
                right = middle;		// 新区间[left, middle)
            }
            else if (nums[middle] < target) {
                left = middle + 1;		// 新区间[middle+1, right)
            }
            else {
                return middle;
            }
        }
        return -1;
    }
};

leetcode35.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int middle = 0;
        while(left <= right) {
            middle = (left+right)/2;
            if(nums[middle] > target) {
                right = middle - 1;
            }
            else if(nums[middle] < target) {
                left = middle + 1;
            }
            else{
                return middle;
            }
        }
        return target > nums[middle] ? middle + 1 : middle;
    }
};

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

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

// 解法一:用一个二分
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int  left = 0;
        int  right = nums.size() - 1;
        if(nums.size() == 0 || target < nums[left] || target > nums[right]) {
            return {-1, -1};
        }
        while(left <= right) {  
            int middle = (left + right) / 2;
            if(target > nums[middle]) {
                left = middle + 1;
            }
            else if(target < nums[middle]) {
                right = middle - 1;
            }
            else {
                left = right = middle;
                int tmp = middle;
                while(--tmp >= 0) {
                    if(nums[tmp] == nums[middle]) {
                        left = tmp;
                    }
                }
                tmp = middle;
                while(++tmp <= nums.size() - 1) {
                    if(nums[tmp] == nums[middle]) {
                        right = tmp;
                    }
                }
                return {left, right};
            }
        }
        return {-1, -1};
    }
};
// 解法二:用两个二分分别找左边界和右边界
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int leftBorder = getLeftBorder(nums, target);
        int rightBorder = getRightBorder(nums, target);
        if (leftBorder == -2 || rightBorder == -2) return {-1, -1};
        if (rightBorder - leftBorder > 1) return {leftBorder + 1, rightBorder - 1};
        return {-1, -1};
    }
private:
     int getRightBorder(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int rightBorder = -2;
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
                right = middle - 1;
            } else { // 寻找右边界,nums[middle] == target的时候更新left
                left = middle + 1;
                rightBorder = left;
            }
        }
        return rightBorder;
    }
    int getLeftBorder(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int leftBorder = -2;
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
                right = middle - 1;
                leftBorder = right;
            } else {
                left = middle + 1;
            }
        }
        return leftBorder;
    }
};

leetcode69. x的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根。
由于返回类型是整数,结果只保留 整数部分,小数部分将被 舍去 。

class Solution {
public:
    int mySqrt(int x) {
        if(x <= 1) {
            return x;
        }
        int min = 0;
        int max = x;
        while(max - min > 1) {
            int mid = (min + max) / 2;
            if(x/mid < mid) {
                max = mid;
            }
            else {
                min = mid;
            }
        }
        return min;
    }
};

leetcode27. 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

双指针法:通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
快指针:寻找新数组的元素,新数组即不含目标元素的数组
慢指针:指向更新 新数组下标的位置

// 双指针法
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
            if (nums[fastIndex] != val) {
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        return slowIndex;
    }
};
// 暴力解法,找到val后其后元素全体前移
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int len = nums.size();
        for(int i = 0; i < len;i++) {
            if(nums[i] == val) {
                for(int j = i + 1; j < len;j++) {
                    nums[j - 1] = nums[j];
                }
                i--;
                len--;
            }
        }
        return len;
    }
};
// 解法二
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int len = nums.size();
        for(int i = 0; i < len;i++) {
            if(nums[i] == val) {
                nums[i] = nums[len-1];
                i--;
                len--;
            }
        } 
        return len;
    }
};

leetcode26. 删除排序数组中的重复项

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

// 双指针法
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int slow = 0;
        for(int fast = 1; fast < nums.size(); fast++) {
            if(nums[fast] != nums[slow]) {
                nums[++slow] = nums[fast];
            }
        }
        return ++slow;
    }
};

leetcode238. 移动零

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

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int i = 0;
        int j = 0;
        for(i = 0; i < nums.size(); i++) {
            if(nums[i] != 0) {
                nums[j++] = nums[i];
            }
        }
        while(j < nums.size()) {
            nums[j++] = 0;
        }
    }
};

leetcode977.有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序

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

leetcode209.长度最小的子数组

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

滑动窗口法:不断调节子序列的起始位置和终止位置,从而得到想要的结果。
滑动窗口也叫双指针算法,因为两个指针间形成一个窗口

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int res = INT32_MAX;
        int sum = 0;	// 滑动窗口数值之和
        int left = 0;		// 滑动窗口的起始位置
        int subLen = 0;	// 滑动窗口的长度
        for (int right = 0; right < nums.size(); right++) {
            sum += nums[right];
            while (sum >= target) {
                subLen = right - left + 1;
                res = min(res, subLen);
                sum -= nums[left++];	// 不断变更i
            }
        }
        // 如果result未被赋值,即说明没有符合条件的子序列,返回0
        return res == INT32_MAX ? 0 : res;
    }
};

leetcode904.水果成篮

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        unordered_map<int, int> cnt;
        int left = 0;
        int res = 0;
        for (int right = 0; right < fruits.size(); right++) {
            ++cnt[fruits[right]];
            while (cnt.size() > 2) {
                auto it = cnt.find(fruits[left]);
                --it->second;
                if (it->second == 0) {
                    cnt.erase(it);
                }
                ++left;
            }
            res = max(res, right - left + 1);
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值