文章目录
学习目标:
牛客网中级算法题 第一章学习内容:
1.旋转词-模拟
2.旋转矩阵-模拟
3.数轴覆盖-贪心
4.1 完整字符串1(括号字符串的有效性)-栈
4.2 完整字符串2(缺失的括号)-栈
4.3 完整字符串3(最长合法括号子串)-栈
5.打包机器人-贪心
6.1容器装水-贪心
6.2地形盛水-贪心
7.牛牛找工作-有序表
8.安置路灯-贪心
学习时间:
2022.3.1-2022.3.6
学习产出:
1.旋转词-模拟
牛客网题目连接
如果一个字符串为str,把字符串的前面任意部分挪到后面形成的字符串叫str的旋转词。比如str=“12345”,str的旋转串有“12345”、“45123”等等。给定两个字符串,判断是否为旋转词。
解析:
1.备注时间复杂度和空间复杂度为O(N),这就表示,我们不能用暴力法去求解了。
2.我们通过仔细阅读题目,不难发现,如果旋转词的长度和原来串的长度不一致,那么肯定是NO
3.我们使用的方法是,扩大串。将str= str + str
4.所以我们的算法的难度来到了KMP,这是一个经典的判断字串的算法
using System;
namespace test{
class test{
static void Main(string[] args){
string lengthIn=Console.ReadLine();
string[] lengthSplit=lengthIn.Split(' ');
int length1=Convert.ToInt32(lengthSplit[0]);
int length2=Convert.ToInt32(lengthSplit[1]);
if(length1!=length2){
Console.WriteLine("NO");
return;
}
string l1=Console.ReadLine();
string l2=Console.ReadLine(); //第二个字符串
//让字符串扩大两倍
string big=l1+l1;
for(int i=0;i<big.Length;i++){
if(big[i]==l2[0]){
if(IsChild(i,big,l2)){
Console.WriteLine("YES");
return;
}
}
}
Console.WriteLine("NO");
}
//KMP
static bool IsChild(int begin,string father,string child){
int childindex=0;
for(int i=begin;i<father.Length;i++){
if(father[i]!=child[childindex]){
return false;
}
childindex++;
if(childindex>=child.Length)return true;
}
return true;
}
}
}
总结:这里我们采用基地址的方法,以每个基地址作为处理对象,通过将每个基地址的情况进行计算,得到最优的答案。
局部->最优
2.旋转矩阵-模拟
牛客网链接
有一个NxN整数矩阵,请编写一个算法,将矩阵顺时针旋转90度。
给定一个NxN的矩阵,和矩阵的阶数N,请返回旋转后的NxN矩阵。
解析:
1.其实我们可以创新一个新的矩阵,然后将旧矩阵旋转之后,赋值给新矩阵,只需要找到对应点旋转后的关系即可。
2.但是,进阶要求是要我们去实现空间复杂度为O(1),意思就是不创建新的矩阵,就在原来的矩阵里面进行旋转
3.我们采取剥洋葱的方法,一层一层的去实现旋转。首先是最外面一层,我们的发现他们的规律,红色的组一,就是四个顶点,他们旋转的位置很容易发现规律。我们只需要用一个去覆盖另外一个即可。然后紧跟着的绿色组二,和组一位置的关系很紧密,看下面写的for循环就可以理解了。
4.for循环的一次循环,代表完成一组。比如i=0,执行完后,组1完成旋转。比如i=1,执行完成后,组2完成选择。所以,一个for循环,就可以解决一圈的数据
5.我们只需要让abcd的值,不断往里面缩。下一个圈,就是a+1,b+1,c-1,d-1
6.直到a>c了,就是都完成了
using System;
class Solution
{
public int[][] rotateMatrix(int[][] mat, int n)
{
int a=0;
int b=0;
int c=n-1;
int d=n-1;
while(a<c){
RotateOne(mat,a++,b++,c--,d--);
}
PrintMat(mat,n);
return mat;
}
public static void RotateOne(int[][] mat,int a,int b,int c,int d){
for(int i=0;i<d-b;i++){
int temp=mat[a][b+i];
mat[a][b+i]=mat[c-i][b];
mat[c-i][b]=mat[c][d-i];
mat[c][d-i]=mat[a+i][d];
mat[a+i][d]=temp;
}
}
public static void PrintMat(int[][] mat,int n){
Console.Write('[');
for(int i=0;i<n;i++){
Console.Write('[');
for(int j=0;j<n;j++){
Console.Write(mat[i][j]);
Console.Write(',');
}
Console.Write(']');
}
Console.Write(']');
}
}
总结:
这道题我们应该舍弃局部,而是从整体来进行处理。以整体去推局部,如果纠结于某个局部的值怎么样去转换, 那会很难!
如果我们分析整体,发现客观规律,那我们就可以轻松应对。
将局部代入整体
3.数轴覆盖-贪心
牛客网链接
分析:
1.这里使用的是3方法,滑动窗口法。以Left作为窗口左边,Right作为窗口右边。Right试着往右边无限扩大窗口,直到无法扩大,即让Left往前移动一格。每一次右边无法扩大的时候,即是Left位置窗口的最大值。此时应该刷新Max。
using System;
namespace test{
class test{
static void Main(){