力扣第196场周赛题解

比赛心得: 本次比赛的经历让我大致地了解到了力扣周赛的难度:主要是前两题比较简单、第三题难度加深、最后一题相比来说最难。随着难度层次的逐渐加深,知识点也逐渐增多,而且周赛涉及到的知识点也比较广泛,是一种很好的测验和检验水平的方法。

一、 判断能否形成等差数列

知识点:排序、遍历
分析:简单题,遍历即可

给你一个数字数组 arr 。
如果一个数列中,任意相邻两项的差总等于同一个常数,那么这个数列就称为 等差数列 。
如果可以重新排列数组形成等差数列,请返回 true ;否则,返回 false 。

class Solution {
public:    
	bool canMakeArithmeticProgression(vector<int>& arr) {
		sort(arr.begin(),arr.end());        
		int d=arr[1]-arr[0];        
		for(int i=2;i<arr.size();i++)        
		{            
			if(arr[i]-arr[i-1]!=d)                
			return false;        
		}        
		return true;    
	}
};

二 、所有蚂蚁掉下来前的最后一刻

知识点:遍历、求最值
分析:两只蚂蚁在碰到之后反向走,但实质上只是交换了身份,从全局来看并没有什么影响。找到隔目标端点最远的蚂蚁即可

有一块木板,长度为 n 个 单位 。一些蚂蚁在木板上移动,每只蚂蚁都以 每秒一个单位 的速度移动。其中,一部分蚂蚁向 左 移动,其他蚂蚁向 右 移动。
当两只向 不同 方向移动的蚂蚁在某个点相遇时,它们会同时改变移动方向并继续移动。假设更改方向不会花费任何额外时间。
而当蚂蚁在某一时刻 t 到达木板的一端时,它立即从木板上掉下来。
给你一个整数 n 和两个整数数组 left 以及 right 。两个数组分别标识向左或者向右移动的蚂蚁在 t = 0 时的位置。请你返回最后一只蚂蚁从木板上掉下来的时刻。

class Solution {
public:
    int getLastMoment(int n, vector<int>& left, vector<int>& right) {
            //脑筋急转弯题,两只蚂蚁在碰到之后反向走,但实质上只是交换了身份,从全局来看并没有什么影响
            //所以本题是找隔目标端点最远的蚂蚁
            int l=0,r=n;
            for(int i=0;i<left.size();i++)        
            {            
            	l=max(l,left[i]);
            }        
            for(int i=0;i<right.size();i++)        
            {         
            	r=min(r,right[i]);        
            }        
            return max(l,n-r);    
       }
};

三、统计全 1 子矩形

知识点:遍历、枚举
分析:从最后的运行结果来看,虽然这种方法和其他人的动归相比时间复杂度上有一定的差距(但是差距不大,也远没有超时),但是这样写的空间复杂度很低。这种思路每次只计算ij右下角能组成的矩形,是一种思路比较简单的方法

给你一个只包含 0 和 1 的 rows * columns 矩阵 mat ,请你返回有多少个 子矩形 的元素全部都是 1 。

class Solution {
public:
    int numSubmat(vector<vector<int> >& mat) {
        int res=0;
        for (int i = 0; i < mat.size() ; ++i) {
            for (int j = 0; j < mat[i].size(); ++j) {
                if(mat[i][j]==0) continue;
                
                //每次只计算ij右下角能组成的矩形
                int r=mat[0].size();
                for (int p = i; p < mat.size(); ++p) {
                    for (int q = j; q <r ; ++q) {   //从ij开始往下找
                        if (mat[p][q]==0){     //一旦碰到0则更新边界并跳出这层循环
                            r=q;
                            break;
                        }
                        res++;
                    }
                }
            }
        }
        return res  ;
    }
};
运行结果:
执行用时:108 ms, 在所有 C++ 提交中击败了52.97%的用户
内存消耗:13.3 MB, 在所有 C++ 提交中击败了100.00%的用户

四、最多 K 次交换相邻数位后得到的最小整数

知识点:递归,字符串处理
分析:本问题主要实现方法是找出字符串中最小的一位数,并通过其位数的次数把它移到最前面,并递归重复此步骤,基本思路已在注释中写出。但这样做时间复杂度比较高,想到复杂度更低的方法了我会及时改进

给你一个字符串 num 和一个整数 k 。其中,num 表示一个很大的整数,字符串中的每个字符依次对应整数上的各个数位 。
你可以交换这个整数相邻数位的数字 最多 k 次。
请你返回你能得到的最小整数,并以字符串形式返回。

class Solution {
public:
    string minInteger(string num, int k) 
    {
        //前两个if尽早排除k值太大或者其他特殊情况,以免测试用例设计使代码超时
        if (k>num.size()*(num.size()-1)/2)  
        {
            sort(num.begin(),num.end());
            return num;
        }
        if (k<=0) return num;
        char Min='9'+1; //Ascll的'9'+1
        int t=0; //用于递归

        for (int i = 0; i <num.size()&& i<=k ; ++i) 
        {
            if (num[i]<Min)
            {
                Min=num[i]; //更新最小值
                t=i;
                if (Min=='0')
                {
                    //开始首位就是0的特殊情况
                    if (i==0) return '0'+minInteger(num.substr(1),k);
                    //中间位t有0的情况,要交换t次
                    return '0'+minInteger(num.substr(0,t)+num.substr(t+1),k-t);  
                }
                
            }
        }
        //优先把最小的在t位的数拿到最前面,此过程消耗t步。依此进行递归
        return Min+minInteger(num.substr(0,t)+num.substr(t+1),k-t); 
    }
};

你可能感兴趣的:(力扣周赛题解)