数据结构--LeetCode专题练习 Day10

240. 搜索二维矩阵 II

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
 

示例 1:

 输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出:true


示例 2:

 输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20
输出:false

提示:

m == matrix.length
n == matrix[i].length
1 <= n, m <= 300
-10 9 <= matix[i][j] <= 10 9
每行的所有元素从左到右升序排列
每列的所有元素从上到下升序排列
-10 9 <= target <= 10 9

原始思路:

从左下角开始,比较上和右,上为小,右为大 2.根据target值选择上或右,知道找到target为止
当前数比目标元素小,当前列就不可能存在目标值,“指针”就向右移一格;
如果当前数比目标元素大,当前行就不可能存在目标值,“指针”就向上移一格

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
    int m = matrix.size();
        if (m == 0) {
            return false;
        }
        int n = matrix[0].size();
        if (n == 0) {
            return false;
        }


        // 起点:左下角
        int x = m - 1;
        int y = 0;
        // 不越界的条件是:行大于等于 0,列小于等于 cols - 1
        while (x >= 0 && y < n) {
            if (matrix[x][y] > target) {
                x--;
            } else if (matrix[x][y] < target) {
                y++;
            } else {
                return true;
            }
        }
        return false; 
    }
};//88 ms 14.6MB

其他思路:

1.暴力法

找到了,返回 true

否则,对于搜索到末尾都没有返回的循环,返回 false

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
		for(int i=0;i<matrix.size();i++){
			for(int j=0;j<matrix[0].size();j++){
				if(matrix[i][j]==target){
					return true;
				}
			}
		}
		return false;
	}
};

2.二分查找
一行一行的进行二分查找即可
/*某一行的第一个元素大于了 target ,当前行和后边的所有行都不用考虑了,直接返回 false。
某一行的最后一个元素小于了 target ,当前行就不用考虑了,换下一行。*/

class Solution {
    int m, n;
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        m = matrix.size(), n = matrix[0].size();
        for(int i = 0; i < m; ++i)
            if(binarySearch(matrix, i, target)) return true;
        return false;
    }

    bool binarySearch(vector<vector<int>>& matrix, int i, int target)
    {
        int left = 0, right = n;
        while(left < right)
        {
            int mid = left + (right - left)/2;
            if(target > matrix[i][mid]) left = mid + 1;
            else    if(target < matrix[i][mid])    right = mid;  
            else    return true; 
        }
        return false;
    }
};

3.单二分  

行 是单调递增的特性
利用STL库函数 binary_search 做查找

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        for (auto &i : matrix)
            if (binary_search(i.begin(), i.end(), target)) return true;
        return false;
    }
};

4.双二分  

把 行/列 单调递增的特性都用到

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        return searchMatrix(matrix, target, 0, matrix.size() - 1);
    }

private:
    bool searchMatrix(vector<vector<int>>& matrix, int target, int t, int d) {
        if (t > d) return false;
        int mid = t + (d - t) / 2;
        return searchTarget(matrix[mid], target) || // 查找中间
            searchMatrix(matrix, target, t, mid - 1) || // 查找上半部
            searchMatrix(matrix, target, mid + 1, d) ; // 查找下半部
    }

    bool searchTarget(vector<int> &m, int target) {
        int l = 0, r = m.size() - 1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if (m[mid] == target) return true;
            m[mid] > target ? r = --mid : l = ++mid;
        }
        return false;
    }
};

435. 无重叠区间

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。

注意:

可以认为区间的终点总是大于它的起点。
区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。

示例 1:

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

输出: 1

解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

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

输出: 2

解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

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

输出: 0

解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

原始思路:
输出需要移除的区间个数(最少去除多少个)贪心
如何判别重叠?去掉重复区间;给区间设置left和right指针 1.首先按照左区间排序
2.选择左区间和有区间最小的那个区间作为开始区间
3.选择>=右区间的左区间作为下一个区间,且区间长度最短(该区间的right最小)

思路更正:

按照左边界排序,就要从右向左遍历,因为左边界数值越大越好(越靠右),这样就给前一个区间的空间就越大,所以可以从右向左遍历。
从左向右记录非交叉区间的个数。最后用区间总数减去非交叉区间的个数就是需要移除的区间个数了
每次取非交叉区间的时候,都是可右边界最小的来做分割点
题目只是要求移除区间的个数,没有必要去真实的模拟删除区间

难点:
难点一:有感觉需要排序,但究竟怎么排序,按左边界排还是右边界排。
难点二:排完序之后如何遍历,如果没有分析好遍历顺序,那么排序就没有意义了。
难点三:直接求重复的区间是复杂的,转而求最大非重复区间个数。
难点四:求最大非重复区间个数时,需要一个分割点来做标记。

class Solution{
public:
	//按照右边界排序,1代表右
	static bool cmp(const vector<int>&a,const vector<int>&b){
		return a[1]<b[1];
	}
	int eraseOverlapIntervals(vector<vector<int>>& intervals){
			if(intervals.size()==0) return 0;
			sort(intervals.begin(),intervals.end(),cmp);//按右边界排序
			int count=1;//记录非交叉区间个数
			int end=intervals[0][1];//记录区间分割点
			for(int i=1;i<intervals.size();i++){ //遍历
				if(end<=intervals[i][0]){  //分割点<左区间
					end=intervals[i][1];//其右区间等于新的分割点
					count++;//非交叉区间加一
				}
			}
			return intervals.size()-count;
		}
	}
};

其他思路:

动态规划
先将所有的n个区间按照左端点(或者右端点)从小到大进行排序,随后使用动态规划的方法求出区间数量的最大值
在所有满足要求的j中,选择fj最大的那一个进行状态转移,如果找不到满足要求的区间,那么状态转移方程中min 这一项就为0,fi就为1 
最终的答案即为所有fi中的最大值
状态转移方程:fi=max{fj}+1  fi表示以区间i为最后一个区间,选出区间数量最大值

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
		if(intervals.empty()){
			return 0;
		}
		sort(intervals.begin(),intervals.end(),[](const auto&u, const auto& v){
			return u[0]<v[0];
		});//将比较方法和比较函数写在了一起

		int n=intervals.size();
		vector<int>f(n,1);
		for(int i=1;i<n;++i){
			for(int j=0;j<i;++j){
				if(intervals[j][1]<=intervals[i][0]){
					f[i]=max(f[i],f[j]+1);//动态规划方程
				}
			}
		}
		return n-*max_element(f.begin(),f.end());
	}
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值