算法 64式 7、搜索算法整理_第5部分_61到75题

1 算法思想

算法分类

搜索算法主要分为:

暴力搜索+剪枝,枚举,广度优先搜索,深度优先搜索,二分查找,哈希查找, A*算法,两边向中间逼近,从中间向两边扩散等

 

1.1枚举

枚举: 最直白的搜索方式,依次尝试搜索空间中的所有解。可以在搜索过程中通过加强条件约束来减少搜索范围图。

例如: 百鸡问题

 

1.2广度优先搜索(BFS)

含义:遍历解答树时使每次状态转移时扩展出尽可能多的状态,并按照各状态出现顺序依次扩展它们。

表现:在解答树上表现为树的层次遍历。

适用:可用于求解最优问题。因为其搜索到的状态总是按照某个关键字递增(例如时间,倒杯次数等)。一旦问题中出现最少,最短,最优等关键字,

       就需要考虑是否使用广度优先搜索。

实现: 一般用队列实现,用结构体保存每个状态,用标记数组防止无效搜索。

实现过程:

1)定义结构体用于保存每个状态,定义标记数组防止无效搜索

2)初始化第一个元素,并将该元素塞入队列中,设置第一个元素为已经访问

3)只要队列非空,得到并弹出队头元素,扩展得到新的元素,

对每个新元素,判断其如果满足约束条件并且是未遍历过的,

则更新新元素的状态,并将新元素塞入队列,设置新元素为已经访问过,

如果新元素是所求解,则直接返回

剪枝: 剪去解答树上不可能存在答案的子树。

 

1.3深度优先搜索(DFS)

含义: 优先遍历层次更深的状态,直到遇到一个状态节点不再拥有子树,则返回上一层,

访问其未被访问过的子树,直到解答树中所有状态被遍历完成。

适用: 深度优先搜索缺少广度优先搜索按层次递增顺序遍历的特性,深度优先搜索到的状态不再具有最优特性,深度优先搜索更多求解的是有解或者无解的问题。

实现: 通常使用递归实现。

实现过程:

1)扩展得到新元素,如果新元素不符合约束条件,则过滤该新元素;

2)基于当前状态更新得到新元素状态,判断新元素状态是否等于所求状态,如果是,设置结果标记为成功并直接返回;

3)否则,设置新元素为已经访问,递归处理,设置新元素为未访问(因为后续状态全部遍历完成,需要退回上层状态),如果结果标记为成功,则停止搜索

1.2 特点

1.3适用

1.4通用解法

广度优先搜索(BFS)算法:

1)定义结构体用于保存每个状态,定义标记数组防止无效搜索

2)初始化第一个元素,并将该元素塞入队列中,设置第一个元素为已经访问

3)只要队列非空,得到并弹出队头元素,扩展得到新的元素,

对每个新元素,判断其如果满足约束条件并且是未遍历过的,

则更新新元素的状态,并将新元素塞入队列,设置新元素为已经访问过,

如果新元素是所求解,则直接返回

 

 

深度优先搜索(DFS)算法:

1)扩展得到新元素,如果新元素不符合约束条件,则过滤该新元素;

2)基于当前状态更新得到新元素状态,判断新元素状态是否等于所求状态,如果是,设置结果标记为成功并直接返回;

3)否则,设置新元素为已经访问,递归处理,设置新元素为未访问(因为后续状态全部遍历完成,需要退回上层状态),如果结果标记为成功,则停止搜索

 

 

1.5经典例题讲解

广度优先搜索(BFS):

胜利大逃亡

我被魔王抓走,城堡是A*B*C的立方体,即A个B*C的矩阵,我被关在(0,0,0)位置,出口在(A-1,B-1,C-1),魔王在T分钟内回到城堡,

我每分钟能移动1个坐标。若走到出口恰遇魔王,也算成功。请输出多少分钟可以离开,不能则输出-1

代码:

typedef struct Stat                //定义结构体用于保存每个状态

{

       int x,y,z;//坐标

       int t;//从(0,0,0)到达该坐标的时间

}Stat;//保存当前节点的状态

 

int maze[N][N][N];//用于标识每一个坐标是0:路,1:墙

bool mark[N][N][N];// 定义标记数组防止无效搜索,用于标识该坐标是否已经搜索过,false:未搜索过,true:搜索过,便于剪枝

int goNext[][3] =

{1,0,0,

-1,0,0,

0,1,0,

0,-1,0,

0,0,1,

0,0,-1};//用于进行下一次6个可达状态的遍历

 

queue<Stat> queueStat;

 

//进行深度遍历,无需判断超时

int BFS(int a,int b,int c)

{

       //只要队列不空,说明仍有状态需要遍历

       while(!queueStat.empty())

       {

              //弹出当前状态,进行状态迁移

              Stat stat = queueStat.front();

              queueStat.pop();

 

              //遍历6种状态,扩展得到新的元素

              int x,y,z;

              for(int i = 0 ; i < 6 ; i++)

              {

                     x = stat.x + goNext[i][0];

                     y = stat.y + goNext[i][1];

                     z = stat.z + goNext[i][2];

 

                     //对每个新元素,判断其如果满足约束条件并且是未遍历过

// 判断是否仍在围墙中

                     //易错,这里城堡的位置是不能为a,因为这是数组,这样做就超过了

                     //if(x < 0 || x > a || y < 0 || y > b || z < 0 || z > c)

                     if(x <0 || x >= a || y < 0 || y >=b || z < 0 || z >= c )

                     {

                            continue;

                     }

 

                     //如果已经遍历过,则跳过

                     if(true==mark[x][y][z])

                     {

                            continue;

                     }

                     //如果下一个是墙,则跳过

                     if(1==maze[x][y][z])

                     {

                            continue;

                     }

 

                     //更新新元素的状态,并将新元素塞入队列,设置新元素为已经访问过

                     Stat statTemp;

                     statTemp.x = x;

                     statTemp.y = y;

                     statTemp.z = z;

                     statTemp.t = stat.t + 1;//所耗时间进行累加

 

                     //易错,更新剪枝状态

                     mark[x][y][z] = true;

 

                     //将新状态放入队列

                     queueStat.push(statTemp);

 

           //如果新元素是所求解,则直接返回

                     //判断是否已经到达终点,则返回其所耗时间

                     if(a-1==x && b-1==y && c-1==z)

                     {

                            return statTemp.t;

                     }

              }//for

       }//while

       return -1;//如果一直没有找到,返回-1

}

 

 

深度优先搜索(DFS)

Temple of the bone

有一个N*M的迷宫,起点S,终点D,墙X和地面,'.'表示路,0秒时,我从S出发,

每秒能走到4个与其相邻位置的任意一个,行走之后不能再次走入。

问:是否存在一条路径使主人公刚好在T秒走到D

代码

typedef struct Stat

{

       int x,y;//横纵坐标

       int t;//耗费时间

}Stat;

 

char maze[N][N];//保存迷宫元素

bool success;//设置是否找到的成功标记

 

//走下一个位置的数组

int goNext[][2] =

{0,1,

-1,0,

1,0,

0,-1

};

 

//深度优先搜索

void DFS(int x,int y,int t,int n,int m,int tLimit)

{

       int i ;

    // 扩展得到新元素

       for(i = 0 ; i < 4 ; i ++)

       {

              int iXNext = x + goNext[i][0];

              int iYNext = y + goNext[i][1];

 

        // 如果新元素不符合约束条件,则过滤该新元素

              //判定有无超过迷宫位置

              if(iXNext < 1 || iXNext > n || iYNext < 1 || iYNext > m)

              {

                     continue;

              }

              //判定是否是墙

              if('X'==maze[iXNext][iYNext])

              {

                     continue;

              }

        // 基于当前状态更新得到新元素状态,判断新元素状态是否等于所求状态,如果是,设置结果标记为成功并直接返回

              //判定是否到达终点,并且时间要符合

              if('D'==maze[iXNext][iYNext] && tLimit==(t + 1))

              {

                     //易错,需要设置成功标记

                     success = true;

                     return;

              }

       

        //设置新元素为已经访问,递归处理,设置新元素为未访问(因为后续状态全部遍历完成,需要退回上层状态),如果结果标记为成功,则停止搜索

              maze[iXNext][iYNext] = 'X';

              //递归调用

              DFS(iXNext,iYNext,t+1,n,m,tLimit);

              //若其后续状态全部遍历完毕,返回上层状态,因为要搜索后续状态,因此再将墙改为普通状态

              maze[iXNext][iYNext] = '.';

 

              //易错,判断是否搜索成功

              if(true==success)

              {

                     return;

              }

       }//for

       //如果一直遍历不到,则返回-1

       return;

}

 

 

2 搜索系列

类别-编号

题目

遁去的1

61

如何在不能使用库函数的条件下计算n的平方根

给定一个数n,求出它的平方根,比如16的平方根是4.要求不能使用库函数。

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/96723712

关键:

1 二分查找尤其需要注意一种情况

while low < high:

  low = high - 1

  此时会造成无限循环,

  当low = high - 1 需要跳出循环再计算

2 书上解法

通过近似值获取。第一个近似值为1,接下来的近似值通过

Ai+1 = (Ai + n/Ai)/2

为什么?

3 没有想到

没有想到公式:

Ai+1 = (Ai + n/Ai)/2

 

代码:

# 其中e是精度

def squareRoot(n, e):

    newOne = n

    lastOne = 1.0 # 第一个近似值

    while newOne - lastOne > e:

        newOne = (newOne + lastOne) / 2

        lastOne = n / newOne

    return newOne

 

 

def process():

    # for i in range(0, 27):

    #     result = rootOfN(i)

    #     print results

    e = 0.000001

    for i in range(0, 27):

        result = squareRoot(i, e)

        print result

62

黑白图像

输入一个n*n的黑白图像(1表示黑色,0表示白色),任务是统计其中八连块的个数。如果两个黑盒子有公共边或者公共顶点,就说它们属于同一个八连块。

如图所示,有3个八连块

输入:

6

100100

001010

000000

110000

111000

010100

输出:

3

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47730863

#define MAXSIZE 50

int iPic[MAXSIZE][MAXSIZE];

int iMark[MAXSIZE][MAXSIZE];

int go[][2] =

{

       {-1,1},

       {0,1},

       {1,1},

       {-1,0},

       {1,0},

       {-1.-1},

       {0,-1},

       {1,-1}

};

 

void dfs(int x,int y,int n)

{

       int iNextX,iNextY;

       for(int i = 0; i < 8;i++)//八个方向

       {

              iNextX = x + go[i][0];

              iNextY = y + go[i][1];

              if(iNextX < 1 || iNextX > n || iNextY < 1 || iNextY > n)//越界

              {

                     continue;

              }

              if(iMark[iNextX][iNextY])//已经访问过

              {

                     continue;

              }

              if(!iPic[x][y])//如果是白色

              {

                     continue;

              }

              //先置当前节点为已经访问过

              iMark[iNextX][iNextY] = 1;

              dfs(iNextX,iNextY,n);

              //如果达到要求

             

              //iMark[iNextX][iNextY] = 0;//由于是深度访问,还要将已访问还原。不需要还原,因为这个问题不是那种不成功需要回溯的题目

       }

}

 

void process()

{

       int n;

       scanf("%d",&n);

       memset(iMark,0,sizeof(iMark));//初始化未被访问

       for(int i = 1; i <= n;i++)

       {

              for(int j =1 ; j <= n;j++)

              {

                     scanf("%d",&iPic[i][j]);

              }

       }

       int iCount = 0;

       for(int k = 1; k <= n; k++)

       {

              for(int p = 1; p <= n; p++)

              {

                     if(!iMark[k][p] && iPic[k][p])//如果未访问和是黑色就开始访问

                     {

                            dfs(k,p,n);

                            iCount++;

                     }

              }

       }

       printf("%d\n",iCount);

}

63

迷宫
一个网格迷宫由n行m列单元格组成,每个单元格要么是空地(用1表示),要么是障碍物(用0表示)。你的任务是找一条从起点到终点的最短移动序列,其中UDLR分别

表示往上、下、左、右移动到相邻单元格。任何时候都不能在障碍格中,也不能走到迷宫之外。起点和终点保证是空地。n,m<=100。

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47730893

关键:

1 在迷宫问题中不管使用bfs还是dfs算法,都不需要再递归后,将剪枝状态进行回溯,因为一旦遇到墙,说明这条路是不通的,因此标记这个路是已经访问过,后序

  不需要再访问,而对于回溯问题,由于若采用当前状态不成功的话,要回溯到上一个状态,而当前状态后续中还有可能被用到,因此需要改变状态

2 bfs一定是最优问题,所以不要考虑是不是最优解,输出的一定是最优解,因为无效解已经被排除了

3                  if(iNextX == iEx && iNextY == iEy)//如果抵达终点,直接返回,放在最后判断,不影响递归

                     {

                            return newStat.time;

                     }

 

代码:

#define MAXSIZE 50

using namespace std;

typedef struct Stat

{

       Stat(int _x,int _y,int _time):x(_x),y(_y),time(_time){}

       int x,y;

       int time;

}Stat;

 

int go[][2] =

{

       {0,1},

       {1,0},

       {0,-1},

       {-1,0}

};

 

queue<Stat> queueStat;

 

int iMap[MAXSIZE][MAXSIZE];

int iMark[MAXSIZE][MAXSIZE];

int iBx,iBy;

int iEx,iEy;

int N,M;

bool isFind = false;

int bfs()//返回所耗时间

{

       while(!queueStat.empty())

       {

              Stat stat = queueStat.front();

              queueStat.pop();

              for(int i = 0 ; i < 4 ; i++)

              {

                     int iNextX = stat.x + go[i][0];

                     int iNextY = stat.y + go[i][1];

                     if(iNextX < 0 || iNextX >= N || iNextY < 0 || iNextY >= M)//越界

                     {

                            continue;

                     }

                     if(iMark[iNextX][iNextY])//已经被访问过

                     {

                            continue;

                     }

                     if(!iMap[iNextX][iNextY])//如果是墙,1表示路,0表示墙,最后的终点必须是路为1

                     {

                            continue;

                     }

                     Stat newStat(iNextX,iNextY,stat.time+1);

                     iMark[iNextX][iNextY] = 1;//置已经访问标记

                     queueStat.push(newStat);

                     if(iNextX == iEx && iNextY == iEy)//如果抵达终点,直接返回,放在最后判断,不影响递归

                     {

                            return newStat.time;

                     }

              }

       }

       return -1;//如果一直没有找到

}

64

迷宫路径
一个网格迷宫由n行m列单元格组成,每个单元格要么是空地(用1表示),要么是障碍物(用0表示)。你的任务是找一条从起点到终点的最短移动序列,其中UDLR分别

表示往上、下、左、右移动到相邻单元格。任何时候都不能在障碍格中,也不能走到迷宫之外。起点和终点保证是空地。n,m<=100。

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47730937

关键:

1 要设置父节点和从父节点到当前节点的走向,两个数组

 

代码:

 

#define MAXSIZE 50

int queue[MAXSIZE*MAXSIZE];

//int father[MAXSIZE*MAXSIZE];

int father[MAXSIZE][MAXSIZE];

int dist[MAXSIZE][MAXSIZE];

int last_dir[MAXSIZE][MAXSIZE];//记录从父节点到子节点的移动序列

int dir[MAXSIZE*MAXSIZE];//方向序列

char name[MAXSIZE] = "RDLU";//方向解释

int iMark[MAXSIZE][MAXSIZE];

int iMaze[MAXSIZE][MAXSIZE];

int go[][2] =

{

       {1,0},//0表示右

       {0,-1},//1表示往下

       {-1,0},//2表示往左

       {0,1}//3表示往上

};

int m;//列数

int n;//行数

int iEx,iEy;

 

void bfs(int x,int y)

{

       memset(iMark,0,sizeof(iMark));

       int front,rear,pos;

       front = rear = 0;

       pos = x*m + y;

       //置已经访问标记和父节点为本身,这个是后面递归的终止条件,距离为0表示,同时将队列中的首元素进行设置

       iMark[x][y] = 1;

       father[x][y] = pos;

       dist[x][y] = 0;

       queue[rear++] = pos;//这个元素,这里其实起到的作用是stat,因为这里无法保存状态,不过写得很搓,程序可读性差

       while(front < rear)

       {

              pos = queue[front++];

              x = pos/m;

              y = pos%m;

              for(int i = 0 ; i < 4 ;i++)

              {

                     int iNextX = x + go[i][0];

                     int iNextY = y + go[i][1];

                     if(iNextX < n && iNextX >= 0 && iNextY < m && iNextY >= 0 && !iMark[iNextX][iNextY] && iMaze[iNextX][iNextY])//这里直接用成立的条件,进行操作,是改进

                     {

                            father[iNextX][iNextY] = pos;

                            pos = iNextX*m + iNextY;

                            queue[rear++] = pos;

                            dist[iNextX][iNextY] = dist[x][y] + 1;

                            last_dir[iNextX][iNextY] = i;

                            if(iNextX == iEx && iNextY == iEy)//找到重点

                            {

                                   return;

                            }

                     }

              }

       }

}

 

void printPath(int x,int y)//这里传入的x和y必须是最后一次走的节点,然后逆向推出其父节点

{

       int c = 0;

       for( ; ; )

       {

              int fx = father[x][y]/m;

              int fy = father[x][y]%m;

              if(x == fx && y == fy)

              {

                     break;//如果没有父节点就退出,是退出条件

              }

              dir[c++] = last_dir[x][y];

              x = fx;

              y = fy;

       }

       while(c--)

       {

              printf("%c ",name[dir[c]]);

       }

}

65

除法

输入正整数,按从小到大的顺序输出所有形如abcde/fghij=n的表达式,其中a~j恰好为数字0~9的一个排列,2<=n<=79.

输入:

62

输出:

79546/01283=62

94736/01528=62

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47731045

关键:

1 暴力解决:罗列所有可能性,一一实验

2 枚举原则:枚举简单的东西:整数,子串

3 应该枚举除数,5个数字,那么被除数算出来之后,看是否有重复的即可,不要傻不拉几的枚举10!种

 

代码:

void division(int n)

{

       if( n <2 || n >79)

       {

              printf("您输入的n不符合要求(2<=n<=79),请重新输入!\n");

              return;

       }

       for(int i = 98765/79; i <= 98765/2; i++)//因为被枚举的数最多不会超过最大数的一半

       {

              int iMark[10] = {0};//用于标记是否有重复元素

              //将数i进行分解

              //这里要加判断,如果被除数小于10000,默认iMark[0] = 1;

              if(i < 10000)

              {

                     iMark[0] = 1;

              }

              int k = i;

              int iProduct;

              bool isOk = true;

              do{

                     int temp = k % 10;//分解个位

                     if(iMark[temp] == 1)

                     {

                            isOk = false;

                            break;

                     }

                     else

                     {

                            iMark[temp] = 1;

                     }

                     k /= 10;

              }while(k);

              if(isOk == false)

              {

                     continue;

              }

              else

              {

                     iProduct = n * i;

                     int p = iProduct;

                     do{

                            int temp = p % 10;

                            if(1 == iMark[temp])

                            {

                                   isOk = false;

                                   break;

                            }

                            else

                            {

                                   iMark[temp] = 1;

                            }

                            p /= 10;

                     }while(p);

              }

              if(isOk)

              {

                     //这里要对除数若小于10000,要前置添加0

                     if(i < 10000)

                     {

                            printf("%d/0%d = %d\n",iProduct,i,n);

                     }

                     else

                     {

                            printf("%d/%d = %d\n",iProduct,i,n);

                     }

              }

       }

}

66

最大乘积

输入n个元素组成的序列S,你需要找出一个乘积最大的连续子序列。如果这个最大的成绩不是整数,应输出-1(表示无解)。1<=n<=18,-10<=Si<=10。

输入:

3

2 4 -3

5

2 5 -1 2 -1

输出:

8

20

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47731081

关键:

1 枚举起点和终点,注意大数要用long long表示 long long iMax = iArr[0]*iArr[1];

2 求最大子段和   max[i] = {max[i-1]*iArr[i],max[i-1] > 0

                       {iArr[i],max[i-1] <= 0,这个只能用于加法,乘法似乎不好用

  for(int i = 0;i < ;i++)

  {

       if(b > 0)

       {

              b += a[i];

       }

       else

       {

              b = a[i]

       }

       if(b > sum)

       {

              sum = b;

       }

  }

 

代码:

#define MAXSIZE 1024

 

void maxProduct()

{

       int n;

       while(EOF != scanf("%d",&n))

       {

              int iArr[MAXSIZE];

              int i;

              for(i = 0;i < n;i++)

              {

                     scanf("%d",&iArr[i]);

              }

              long long iMax = iArr[0]*iArr[1];

              for(int iBegin = 0 ; iBegin <i -1;iBegin++)

              {

                     for(int iEnd = iBegin+1;iEnd <i ; iEnd++)

                     {

                             //int iProduct = 1;

                            long long iProduct = 1;

                             for(int j = iBegin ; j <= iEnd;j++)

                             {

                                   iProduct *=  iArr[j];

                             }

                             if(iProduct > iMax)

                             {

                                   iMax = iProduct;

                             }

                     }

              }

              if(iMax < 0)

              {

                     printf("%d\n",-1);

              }

              else

              {

                     printf("%d\n",iMax);

              }

       }

}

67

分数拆分

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47731123

关键:

1 根据小范围枚举和减法确定另一个数的枚举范围。因为x >= y,有1/x <= 1/y,所以1/k - 1/y <= 1/y解方程组,所以k < y <= 2*k,根据这个,然后将x枚举出来

2 关键是如何求出x,直接减肯定不行1/x = (y-k)/(y*k),所以x = (y*k)/(y-k)

3 float x = 1.0*(y*n)/(y-n);//注意凡是浮点数相乘,不要忘记乘以1.0

4 if(x == temp)//需要判断x是否为整数,先float x一下,再int一下,看是否相等。

 

代码:

void fractionDivision(int n)

{

       int iCount = 0;

       char str[MAXSIZE][50];

       for(int y = n + 1;y <= 2*n;y++)

       {

              float x = 1.0*(y*n)/(y-n);//注意凡是浮点数相乘,不要忘记乘以1.0

              int temp = (int)x;

              if(x == temp)//需要判断x是否为整数,先float x一下,再int一下,看是否相等。

              {

                     sprintf(str[iCount++],"1/%d = 1/%d + 1/%d",n,temp,y);

              }

       }

       printf("%d\n",iCount);

       for(int i = 0; i < iCount;i++)

       {

              puts(str[i]);

       }

}

68

双基回文数

如果一个正整数n至少在两个不同的进位制b1和b2下都是回文数(2<=b1,b2<=10),则称n是双基回文数(注意,回文数不能包含前导0)。输入正整数S<10^6,输出比

S大的最小双基回文数>

输入:1600000(1632994)

输出:1632995

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47731141

思路:

1对比S大每个数进行2到10进制的罗列,这8种中但凡有两种进制回文数相同,就输出

2判断回文数做成一个函数,将一个数先分解(从个位到最高位)存放在一个数组,对这个数组的前一半与后一半进行比较,相同,则认为是回文数

关键:

1 int iMark[11] = {0};//默认标记数组iMark[i]=1表示i进制是回文数,这里进制最大为10,因此iMark必须为11

2 for(p = 0,q = j-1; p < j/2;)//注意这里的j是数组的最后一位,q必须从j-1开始

 

代码:

bool isEchoNum(int n,int *iMark)

{

       for(int b = 2 ;  b <= 10; b++)

       {

              int iArr[MAXSIZE];

              int k = n;

              int j = 0;

              //分解这个数

              do{

                     iArr[j++] = k % b;

                     k /= b;

              }while(k);

              //判断回文

              int p,q;

              bool isEcho = true;

              for(p = 0,q = j-1; p < j/2;)//注意这里的j是数组的最后一位,q必须从j-1开始

              //for(p = 0,q = j;p <= (j-1)/2;)

              {

                     if(iArr[p++] != iArr[q--])

                     {

                            isEcho = false;

                     }

              }

              if(isEcho == true)

              {

                     iMark[b] = 1;

              }

       }

       //判断是不是达到至少两次进制回文

       int iCount = 0;

       for(int m = 2; m <= 10; m++)

       {

              if(iMark[m])

              {

                     iCount++;

              }

       }

       if(iCount >= 2)

       {

              return true;

       }

       else

       {

              return false;

       }

}

 

void doubleBaseEchoNum(int n)

{

       if(n >= 1e7)

       {

              return;

       }

       for(int i = n + 1; ; i++)

       {

              int iMark[11] = {0};//默认标记数组iMark[i]=1表示i进制是回文数,这里进制最大为10,因此iMark必须为11

              memset(iMark,0,sizeof(iMark));

              if(isEchoNum(i,iMark))

              {

                     printf("%d\n",i);

                     break;

              }

       }

}

69

倒水问题

有装满水的6升杯子、空的3升杯子和一升杯子,3个杯子中都没有刻度。在不使用其他道具的情况下,是否可以量出4升的水呢?

输入:

6(满杯水所在的刻度) 3 1

输出:

(6,0,0)->(3,3,0)->(3,2,1)->(4,2,0)

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47746957

思路:

这与倒可乐是一个问题,关键在与状态的搜索。

1 采用广度优先搜索算法

2 当前状态的下一状态的方法为:(a,b,c)

状态:全部分

 

关键:

1 小杯子倒向大杯子,只能全部倒入。大杯子倒向小杯子,把大杯子加满。

2 需要使用倾倒函数。量出4升水的方法是:3升杯装中装2升,1升杯0升,6升杯中为4升。

3 如何打印状态,需要在状态中设置访问标记。设置一个父节点指针,到时候逆向打印即可

4 迷宫是无向图,倒水是有向状态图

 

 

typedef struct Stat

{

       Stat(int a,int b,int c,int d,Stat* s):x(a),y(b),z(c),t(d),par(s){}

       int x;//6升杯中容量

       int y;//3升杯中容量

       int z;//1升杯中容量

       int t;//倾倒次数

       Stat* par;

       //int v;//访问标记,1表示访问

}Stat;

 

queue<Stat> queueStat;

queue<Stat> printStat;

Stat endStat(0,0,0,0,NULL);

//int iCapA,iCapB,iCapC;//3个容器的容量

 

void dump(int iConA,int& iVa,int iConB,int& iVb)//A容器中的水倒向B容器中的水

{

       if(iVa > iConA || iVb > iConB || iVa < 0 || iVb <0)//合法性检验

       {

              return;

       }

       if(iVa + iVb < iConB)//A容器小于B容器,应该加满B

       {

              iVb += iVa;

              iVa = 0;

       }

       else

       {

              iVa -= iConB - iVb;

              iVb = iConB; 

       }

}

 

int  dfs(int iCapA,int iCapB,int iCapC)//当前3个杯子中水的容量

{

       int x,y,z,t;

       while(!queueStat.empty())

       {

              Stat stat = queueStat.front();

              queueStat.pop();

 

              x = stat.x;

              y = stat.y;

              z = stat.z;

              t = stat.t;

              //a向b倾倒

              dump(iCapA,x,iCapB,y);

              if(x < 0 || x > iCapA || y < 0 || y > iCapB || z < 0 || z > iCapC )

              {

                     continue;

              }

              Stat newStat(x,y,z,t+1,&stat);//如果是这样的话,应该保存的是new出来的节点,而且应该保存最后一个状态

              queueStat.push(newStat);

              printStat.push(newStat);

              if(x == 4 && y == 2 && z == 0)//如果找到,就直接退出

              {

                     endStat = newStat;

                     return(t+1);

              }

              else//没找到,生成新状态

              {

                     //Stat newStat(x,y,z,t+1);

                     //queueStat.push(newStat);

                     //printStat.push(newStat);

              }

 

              //a向c倾倒

              x = stat.x;

              y = stat.y;

              z = stat.z;

              t = stat.t;

              dump(iCapA,x,iCapC,z);

              if(x < 0 || x > iCapA || y < 0 || y > iCapB || z < 0 || z > iCapC )

              {

                     continue;

              }

              Stat newStat2(x,y,z,t+1,&stat);

              queueStat.push(newStat2);

              printStat.push(newStat2);

              if(x == 4 && y == 2 && z == 0)//如果找到,就直接退出

              {

                     endStat = newStat2;

                     return(t+1);

              }

 

              x = stat.x;

              y = stat.y;

              z = stat.z;

              t = stat.t;

              //b向a倾倒

              dump(iCapB,y,iCapA,x);

              if(x < 0 || x > iCapA || y < 0 || y > iCapB || z < 0 || z > iCapC )

              {

                     continue;

              }

              Stat newStat3(x,y,z,t+1,&stat);

              queueStat.push(newStat3);

              printStat.push(newStat3);

              if(x == 4 && y == 2 && z == 0)//如果找到,就直接退出

              {

                     endStat = newStat3;

                     return(t+1);

              }

 

              x = stat.x;

              y = stat.y;

              z = stat.z;

              t = stat.t;

              //b向c倾倒

              dump(iCapB,y,iCapC,z);

              if(x < 0 || x > iCapA || y < 0 || y > iCapB || z < 0 || z > iCapC )

              {

                     continue;

              }

              Stat newStat4(x,y,z,t+1,&stat);

              queueStat.push(newStat4);

              printStat.push(newStat4);

              if(x == 4 && y == 2 && z == 0)//如果找到,就直接退出

              {

                     endStat = newStat4;

                     return(t+1);

              }

 

              //c向a倾倒

              x = stat.x;

              y = stat.y;

              z = stat.z;

              t = stat.t;

              dump(iCapC,z,iCapA,x);

              if(x < 0 || x > iCapA || y < 0 || y > iCapB || z < 0 || z > iCapC )

              {

                     continue;

              }

              Stat newStat5(x,y,z,t+1,&stat);

              queueStat.push(newStat5);

              printStat.push(newStat5);

              if(x == 4 && y == 2 && z == 0)//如果找到,就直接退出

              {

                     endStat = newStat5;

                     return(t+1);

              }

 

              //c向b倾倒

              x = stat.x;

              y = stat.y;

              z = stat.z;

              t = stat.t;

              dump(iCapC,z,iCapB,y);

              if(x < 0 || x > iCapA || y < 0 || y > iCapB || z < 0 || z > iCapC )

              {

                     continue;

              }

              Stat newStat6(x,y,z,t+1,&stat);

              queueStat.push(newStat6);

              printStat.push(newStat6);

              if(x == 4 && y == 2 && z == 0)//如果找到,就直接退出

              {

                     endStat = newStat6;

                     return(t+1);

              }

       }

       return -1;

}

70

八数码问题

编号为1~8的8个正方形滑块被摆成3行3列(有一个格子空留),如图所示。每次可以把与空格相邻的滑块(有公共边才算相邻)移到空格中,而它原来的位置就称为了

新的空格。给定初始局面和目标局面(用0表示空格),你的任务是计算出最少的移动步数。如果无法达到目标局面,则输-1.

2     6     4     8  1    5

1     3     7       7  3    6

       5     8     4     2

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47746983

71

八数码问题之哈希去重

输入:

2 6 4 1 3 7 0 5 8

8 1 5 7 3 6 4 0 2

输出:

31

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47746995

72

八数码问题之stl

1set<State> vis,这样只需要调用if(vis.count(s))来判断s是否在集合vis中,并用vis.insert(s)加入集合,用vis.remove(s)从集合中移除s。

问题:并不是所有类型的State都可以作为set中的元素类型。set的元素必须定义"<"运算符,C语言原生的数组(包括字符数组)却不行。

2如果数组不能转化为整数,自己声明结构体,重载函数调用符比较状态。下面中,整数a和b分别是两个状态在状态数组st中的下标,在比较时直接使用memcpy来比较整个

内存块

输入:

2 6 4 1 3 7 0 5 8

8 1 5 7 3 6 4 0 2

输出:

31

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47747019

73

二分查找

本质:有序表中使用二分查找,log2(1000)

深入:

如果数组中多个元素都是v,上面的函数返回的是中间的一个。能不能求出值等于v的完整区间呢?

下面的程序当v存在时返回它出现的第一个位置。如果不存在,返回这样一个下标i:在此处插入v(原来的元素A[i],A[i+1],..全部往后移动一个位置)后序列仍然有序

思路

排序后:

0 1 3 4 6 7 9 9

输入:

8

1 9 6 3 4 7 9 0

3

8

1 9 6 3 4 7 9 0

5

输出:

2

-1

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47747225

74

二分查找之lowerBound

注意:对于二分查找的一个系列,high都是用数组长度来计算,真正是取不到的

如果数组中多个元素都是v,上面的函数返回的是中间的一个。能不能求出值等于v的完整区间呢?

下面的程序当v存在时返回它出现的第一个位置。如果不存在,返回这样一个下标i:在此处插入v(原来的元素A[i],A[i+1],..全部往后移动一个位置)后序列仍然有序

输入:

8

0 1 3 4 6 7 9 9

5

 

8

0 1 4 4 4 4 9 9

4

输出:

4

2

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47747247

重复

int lowerBound(int* iArr,int low,int high,int iVal)//

{

       //while(low <= high)

       while(low < high)//=不能取,陷入死循环,low = high = mid

       {

              int mid = low + (high - low) / 2;

              if(iArr[mid] < iVal)//在右区间

              {

                     low = mid + 1;

              }

              else if(iArr[mid] > iVal)//左区间

              {

                     high = mid;

              }

              else

              {

                     return mid;

              }

       }

       return low;//如果改成low,就是iVal应该在的位置

}

75

二分查找之upperBound


写一个upperBound程序,当v存在时返回它出现的最后一个位置的后面的一个位置。如果不存在,返回这样一个下标i:在此处插入v(原来的元素A[i],A[i+1],..全部

往后移动一个位置)后序列仍然有序。

 

输入:

8

0 1 3 4 6 7 9 9

5

 

8

0 1 3 4 4 4 9 9

4

 

8

0 3 3 4 4 4 9 9

3

输出:

4

6

3

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47747257

 

int upperBound(int* iArr,int low,int high,int iVal)

{

       while(low < high)

       {

              int mid = low + (high - low)/2;

              if(iArr[mid] <= iVal)

              {

                     low = mid + 1;

              }

              else

              {

                     high = mid;

              }

       }

       return high;

}

76

二分查找之范围统计

给出n个整数xi和m个询问,对于每个询问(a,b),输出闭区间[a,b]内的整数xi的个数。

输入:

8

0 1 3 4 6 7 9 9

3 9

输出:

6

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47747273

关键:

1 大于等于a的第一个元素的下标是L。如果所有元素小于a,则L=n

小于等于b的最后一个元素的下一个元素的下标是什么,如果所有元素都大于b,则相当R=0,相当于A[0]前面还有一个A[-1],A[-1]下一个位置为0

答案即为[R-L]的长度,即R-L

2 iterator upper_bound(const key_type& key)返回第一个指向>key的迭代器

3 iterator lower_bound(const key_type& key)返回第一个指向>=key的迭代器

4 return upper_bound(iArr,iArr+n,b) - lower_bound(iArr,iArr+n,a);调用方法是数组首地址和数组元素个数,已经标记值

 

int lowerBound(int* iArr,int low,int high,int iVal)

{

       while(low < high)

       {

              int mid = low + (high - low)/2;

              if(iArr[mid] >= iVal )//在左半区间时,不断向前

              {

                     high = mid;

              }

              else

              {

                     low = mid + 1;

              }

       }

       return low;

}

 

int upperBound(int* iArr,int low,int high,int iVal)

{

       while(low < high)

       {

              int mid = low + (high - low)/2;

              if(iArr[mid] <= iVal)

              {

                     low = mid + 1;

              }

              else

              {

                     high = mid;

              }

       }

       return low;

}

 

int rangeStat_stl(int* iArr,int n,int a,int b)

{

       return upper_bound(iArr,iArr+n,b) - lower_bound(iArr,iArr+n,a);

}

 

int ranggeStat_my(int* iArr,int n,int a,int b)

{

       return upperBound(iArr,0,n,b) - lowerBound(iArr,0,n,a);

}

77

非线性方程求根

一次向银行借a元钱,分b月还清。如果需要每月还c元,月利率是多少(按复利率计算)?例如借2000元,分4个月每月还510,则月利率为0.797%。答案应不超过100%。
输入:

2000 4 510

输出:

0.797%

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47775495

关键:

1 使用猜数字方法,对于百分数,我们把%100提取出来,分子为[0,100]之间的数字,本质上是二分法

2 while(high - low > 1e-5)//利用high-low与精度值的比较来确定循环退出条件

3 本题上下限的更新是根据f(x)的单调性确定,本题单调增,因此,sum>0表明mid选大了,

             if(sum > 0)//说明mid选大了,在小区间

              {

                     high = mid;

              }

4 更新复利的计算表达式为a(1+x)-c,即sum += sum*mid/100.0 - c;//更新剩余所需要还的钱,是加上本月的利息sum*mid/100.0,再减去本月还的钱

 

 

//采用[0,100]区间缩小的方法

void nonlinearEquation(float a,int b,float c)

{

       float low = 0,high = 100;

       while(high - low > 1e-5)//利用high-low与精度值的比较来确定循环退出条件

       {

              float mid = low + (high - low)/2;

              float sum = a;

              for(int i = 0 ; i < b ; i++)

              {

                     sum += sum*mid/100.0 - c;//更新剩余所需要还的钱,是加上本月的利息sum*mid/100.0,再减去本月还的钱

              }

              if(sum > 0)//说明mid选大了,在小区间

              {

                     high = mid;

              }

              else

              {

                     low = mid;

              }

       }

       printf("%.3lf%%\n",low);//要打印出“%”必须连续写两个%%

       //printf("%%\n");

       //printf("%\n");

}

78

统计书中的单词及出现次数,实现一个数据结构进行存储

编程珠玑

https://blog.csdn.net/qingyuanluofeng/article/details/54647029

int getPrimeNumber(int num)

{

       if(num <= 0)

       {

              return -1;

       }

       int* primeArr = new int[num + 1];//用于判定是否为素数的数组,初始化为0,表示都是质数

       // sizeof(指针)都是4,strlen只是用来计算字符串长度,整形指针不行

       int* visitArr = new int[num + 1];//初始化为0,表示都没有访问过

       memset(primeArr , 0 , sizeof(primeArr) * (num + 1));

       memset(visitArr , 0 , sizeof(visitArr) * (num + 1));

       int k;

       for(int i = 2 ; i <= num ; i++ )

       {

              k = i;//k是倍数,从i开始算,不要从2开始, i*i与2*i的比较,起始2*i已经在第一轮计算过了

              while(k * i <= num)

              {

                     //如果没有访问过

                     if(0 == visitArr[i])

                     {

                            visitArr[k * i] = 1;//是k*i不是i

                            primeArr[k * i] = 1;//表示是合数

                     }

                     //如果访问过,就不再处理

                     k++;

              }

       }

       int i;

       //到这里,已经通过素数筛选法,获得了所有质数,凡是primeArr[i]为0都是质数,我们只需要从num向前搜索最接近的质数即可

       for(i = num - 1; i >= 2 ; i--)

       {

              if(0 == primeArr[i])

              {

                     break;

              }

       }

       delete[] primeArr;

       delete[] visitArr;

       return i;

}

 

/*

接下来是要建立散列表,散列表的长度,散列中的乘数为31

散列值计算公式:设一个字符串val共有n个字符,则计算的哈希值为

h = 31 ^ (n-1) * val[0] + 31 ^ (n-2) * val[1] + 31 ^ (n-3) * val[2] + ...+ val[n-1] 

选用31作为乘数的原因是:

  1】对于任意数i, 31 * i = (i << 5) - i,可以用移位和减法代替乘法,可以优化

  2】31是质数,只能被1和自身整除,既要保证31乘以字符串不能溢出,又要保证哈希地址较大,来减少冲突,

  综合来说:31是个不错的乘数

*/

const int MULT = 31;

typedef struct Node

{

       Node():_next(NULL),_word(""),_count(0),_isNULL(true){}

       void setNULL(bool flag)

       {

              _isNULL = flag;

       }

       Node* _next;//指向下一个结点

       //char* _word;//字符串,用字符指针会出现乱码

       string _word;

       int _count;//该字符串出现次数

       bool _isNULL;//初始化建立结点的时候设置结点默认为空,以后每次实例化的结点都必须设置该空为false

}Node;

 

//对字符串进行哈希,返回在哈希表中的下标

int getHash(char* str , int primeNum)

{

       unsigned int hashValue = 0;

       if(NULL == str || primeNum < 2)

       {

              return hashValue;

       }

       for( ; *str ; str++)

       {

              char ch = *str;

              hashValue = MULT * hashValue + ch;

       }

       return (hashValue % primeNum);

}

 

void countWords(Node* hashTable, int primeNum , vector<string> words)

{

       if(NULL == hashTable || primeNum < 2 || words.empty())

       {

              return;

       }

       //对每个单词生成链表

       int size = words.size();

       string sWord;

       char* word;

       int hashIndex;

       Node* node;

       for(int i = 0 ; i < size ; i++)

       {

              sWord = words.at(i);

              word = (char*)sWord.c_str();

              hashIndex = getHash(word , primeNum);

              //如果哈希表中对应位置的结点为空,则需要新建结点

              if(hashTable[hashIndex]._isNULL)

              {

                     Node* newNode = new Node();

                     newNode->_word = sWord;

                     newNode->_isNULL = false;

                     newNode->_count = 1;//设置计数器为1

                     hashTable[hashIndex] = *newNode;

              }

              else

              {

                     //判断对应结点如果不为空,则找到该单词(),并累加计数

                     bool isFind = false;

                     Node* previouNode = NULL;

                     for(node = &hashTable[hashIndex] ; node != NULL ; )

                     {

                            //如果找到该单词

                            if( node->_word == sWord)

                            {

                                   node->_count++;

                                   isFind = true;

                                   break;

                            }

                            previouNode = node;

                            node = node->_next;

                     }

                     //如果一直找不到,说明对应同一个哈希下标,出现了不同的字符串,需要将当前结点加入到首部(发现死循环),插入到尾部

                     if(!isFind)

                     {

                            Node* newNode = new Node();

                            newNode->_word = sWord;

                            newNode->_isNULL = false;

                            newNode->_count = 1;//设置计数器为1

                            previouNode->_next = newNode;

                            //newNode->_next = &hashTable[hashIndex];//插入到首部需要获取地址,似乎陷入了死循环

                            //hashTable[hashIndex] = *newNode;

                     }

              }

       }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

参考:
[1]计算机考研--机试指南,王道论坛 组编
[2]剑指offer
[3]算法设计与分析
[4]编程之美
[5]程序员面试金典
[6]leecode
[7]Python
程序员面试算法宝典
[8]刘汝佳算法竞赛入门经典
[9]算法导论
[10]编程珠玑

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
字节跳动常见算法面试top50整理如下: 1. 两数之和:给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。 2. 两数相加:给定两个非空链表表示两个非负整数,将两数相加返回一个新的链表。 3. 无重复字符的最长子串:给定一个字符串,请找出其中不含有重复字符的最长子串的长度。 4. 两个排序数组的中位数:给定两个大小分别为 m 和 n 的有序数组 nums1 和 nums2,请找出这两个有序数组的中位数。 5. 电话号码的字母组合:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 6. 四数之和:给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a、b、c 和 d,使得 a + b + c + d 的值与 target 相等。 7. 合并两个有序链表:将两个有序链表合并为一个新的有序链表并返回。 8. 验证回文串:给定一个字符串,验证它是否是回文串。 9. 最长有效括号:给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 10. 二叉树的最大深度:给定一个二叉树,找出其最大深度。 11. 盛最多水的容器:给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai)。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 12. 三数之和:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ? 13. 最接近的三数之和:给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。 14. 有效的括号:给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 15. 合并两个有序数组:给定两个有序数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 16. 数组中的第K个最大元素:在未排序的数组中找到第 k 个最大的元素。 17. 罗马数字转整数:将罗马数字转换成整数。 18. 最小路径和:给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和最小。 19. 矩阵置零:给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。 20. 字符串相乘:给定两个以字符串形表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积。 21.有效的数独:判断一个 9x9 的数独是否有效。 22. 旋转图像:给定一个 n × n 的二维矩阵表示一个图像,将图像顺时针旋转 90 度。 23. 搜索旋转排序数组:假设按照升序排序的数组在预先未知的某个点上进行了旋转。 24. 螺旋矩阵:给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 25. 合并K个排序链表:合并 k 个排序链表,返回合并后的排序链表。 26. 不同路径:一个机器人位于一个 m x n 网格的左上角,机器人每次只能向下或者向右移动一步。 27. 跳跃游戏:给定一个非负整数数组,你最初位于数组的第一个位置。 28. 插入区间:给出一个无重叠的,按照区间起始端点排序的区间列表。 29. 最长公共前缀:编写一个函数来查找字符串数组中的最长公共前缀。 30. 螺旋矩阵 II:给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。 31. 编辑距离:给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数。 32. 删除排序链表中的重复元素:给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 33. 字符串转整数(atoi):请你来实现一个 atoi 函数,使其能将字符串转换成整数。 34. 平衡二叉树:给定一个二叉树,判断它是否是高度平衡的二叉树。 35. Pow(x, n):实现 pow(x, n),即计算 x 的 n 次幂函数。 36. 搜索二维矩阵:编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。 37. 接雨水:给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 38. 二进制求和:给定两个二进制字符串,返回它们的和(用二进制表示)。 39. 括号生成:给出 n 对括号,请编写一个函数来生成所有的由 n 对括号组成的合法组合。 40. 逆波兰表达求值:根据逆波兰表示法,求表达的值。 41. 环形链表:给定一个链表,判断链表中是否有环。 42. 环形链表 II:给定一个链表,返回链表开始入环的第一个节点。 43. 重建二叉树:根据一棵树的前序遍历与中序遍历构造二叉树。 44. 验证二叉搜索树:给定一个二叉树,判断其是否是一个有效的二叉搜索树。 45. 二叉树的中序遍历:给定一个二叉树,返回它的中序 遍历。 46. 最小栈:设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。 47. 单词拆分:给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 48. 对称二叉树:给定一个二叉树,检查它是否是镜像对称的。 49. N皇后问:给定一个整数 n,返回所有不同的 n 皇后问的解决方案。 50. 跳跃游戏 II:给定一个非负整数数组,你最初位于数组的第一个位置,在该位 我们的主要任务是根据输入来模拟对话。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值