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

31

Word Search

Given a 2D board and a word, find if the word exists in the grid.

The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.

For example,

Given board =

[

['A','B','C','E'],

['S','F','C','S'],

['A','D','E','E']

]

word = "ABCCED", -> returns true,

word = "SEE", -> returns true,

word = "ABCB", -> returns false.

输入:

3(行数)  ABCCED(待查找字符串)

ABCE

SFCS

ADEE

3  SEE

ABCE

SFCS

ADEE

3  ABCB

ABCE

SFCS

ADEE

1 a

a

1 abc

ab

1 b

a

2 cdba

ab

cd

3  ABCESEEEFS

ABCE

SFES

ADEE

输出:

true

true

false

false

Leecode

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

分析:这是明显的深度优先搜索问题。可以对当前位置(i,j)对应的字符,如果该字符等于给定字符串上对应位置的

字符,说明找到了当前位置。后续进行上下左右4个位置的继续查找,一旦发现位置上的字符不等于给定

单词对应位置字符,立即终止这个方向的搜索

这个不应该是递归,应该是回溯,一旦碰到当前字符不等后,需要回溯到上一个结果。

回溯的话只能判定当前,而不能像递归一样直接尝试下一个,回溯应该是先判定当前是否可能,如果不可能,再做

关键:

1 典型的回溯问题,罗列所有起点+回溯

回溯:一开始就对当前遍历元素的正确和错误状态指出,访问标记一定要先设置,然后回溯结束,重置

回溯开始部分会检查位置是否超出,则递归时无需再检查,这样是重复处理,而且会导致错误

bool dfs(vector<vector<char>>& board, string word, int pos ,int curRow , int curCol , vector<vector<int>>& visited)

{

//找到结果,返回true

if(pos == word.length())

{

return true;

}

int colMax = board.at(0).size();//x最大值为列数

int rowMax = board.size();//y最大值为行数

if(curRow < 0 || curRow >= rowMax || curCol < 0 || curCol >= colMax)

{

return false;

}

if(board.at(curRow).at(curCol) != word.at(pos))

{

//需要回溯

return false;

}

//说明当前是可以继续向下操作的,需要设置访问标记.但是如果是由字符不等,则不需要设置访问标记,因为后续还可能用到

if(visited.at(curRow).at(curCol))

{

return false;

}

visited.at(curRow).at(curCol) = 1;//部分先成功后失败的字符访问标记可能会导致后续查找失败,这里需要重新设置

bool isOk =

dfs(board , word , pos + 1 , curRow + 1 , curCol , visited) ||

dfs(board , word , pos + 1 , curRow - 1 , curCol , visited) ||

dfs(board , word , pos + 1 , curRow , curCol + 1 , visited) ||

dfs(board , word , pos + 1 , curRow , curCol - 1 , visited);

visited.at(curRow).at(curCol) = 0;//回溯需要

return isOk;

}

代码:

int g_next[][2] = {

{-1 , 0},//上

{1 , 0},//下

{0, -1},//左

{0,1}//右

};

class Solution {

public:

bool dfs(vector<vector<char>>& board, string word, int pos ,int curRow , int curCol , vector<vector<int>>& visited)

{

//找到结果,返回true

if(pos == word.length())

{

return true;

}

int colMax = board.at(0).size();//x最大值为列数

int rowMax = board.size();//y最大值为行数

if(curRow < 0 || curRow >= rowMax || curCol < 0 || curCol >= colMax)

{

return false;

}

if(board.at(curRow).at(curCol) != word.at(pos))

{

//需要回溯

return false;

}

//说明当前是可以继续向下操作的,需要设置访问标记.但是如果是由字符不等,则不需要设置访问标记,因为后续还可能用到

if(visited.at(curRow).at(curCol))

{

return false;

}

visited.at(curRow).at(curCol) = 1;//部分先成功后失败的字符访问标记可能会导致后续查找失败,这里需要重新设置

bool isOk =

dfs(board , word , pos + 1 , curRow + 1 , curCol , visited) ||

dfs(board , word , pos + 1 , curRow - 1 , curCol , visited) ||

dfs(board , word , pos + 1 , curRow , curCol + 1 , visited) ||

dfs(board , word , pos + 1 , curRow , curCol - 1 , visited);

visited.at(curRow).at(curCol) = 0;//回溯需要

return isOk;

}

bool exist(vector<vector<char>>& board, string word) {

if(board.empty() || word.empty())

{

return false;

}

int row = board.size();

int col = board.at(0).size();

//罗列所有可能的起始位置

bool isOk;

//设定访问标记

vector< vector<int> > visited( row , vector<int>(col , 0) );

vector< vector<int> > visitedTemp;

int pos;

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

{

for(int j = 0 ; j < col; j++)

{

//每次重新除法,都需要重新设定访问标记

visitedTemp = visited;

pos = 0;

isOk = dfs(board , word , pos , i , j , visitedTemp);

if(isOk)

{

return true;

}

}

}

return false;

}

};

32

Search in Rotated Sorted Array II

Follow up for "Search in Rotated Sorted Array":

What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Write a function to determine if a given target is in the array.

The array may contain duplicates.

Leecode

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

与程序员面试金典题目一样,参见例题16

33

Best Time to Buy and Sell Stock

Contributors: Admin

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Example 1:

Input: [7, 1, 5, 3, 6, 4]

Output: 5

max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price)

Example 2:

Input: [7, 6, 4, 3, 1]

Output: 0

In this case, no transaction is done, i.e. max profit = 0.

分析:给定一个数组,模拟股票价格,要求获取最大利润。也就是从数组中选取两个元素,并且满足较小的元素在前面,较大的元素在后面,

求这样一个差值最大的两个元素。

输入:

6

7 1 5 3 6 4

5

7 6 4 3 1

4

2 1 7 4

5

2 4 1 7 11

输出:

5

0

6

10

Leecode

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

分析:

如果数组降序,直接返回利润为0。问题的关键在于不能简单的去找到最小值和最大值,必须满足较小的元素在前面,较大的元素在后的情况。

因此,如果设定一个指向较小元素指针low从前向后遍历,设定一个指向较大元素的指针high从后向前遍历。

假设数组为A。

如果A[low] >= A[high],不能这样做。指针的走位受到其他元素的影响。这个应该是动态规划。

如果采用暴力破解,罗列每个买入股票的位置和卖出股票的位置,时间复杂度就是O(n^2)

如果采用以当前元素为中心,分别向左和向右扩散的方式,向左找到比自己最小的元素,向右找到比自己最大的元素,然后比较差值

时间复杂度也是O(n^2)

超时,说明有比O(n^2)更好的方法。参考分治的情况。将数组划分成两部分。设数组为A[1...n]

1】如果左边和右边都求出了有差值,记结果分别为

lDiff = lMax - lMin,

rDiff = rMax - rMin

如果lMax <= rMin,diff=rMax - lMin

否则,diff=max(lMax , rMax) - lMin,diff=max(diff ,lDiff, rDiff)

2】左边和右边都没有求出差值,说明都是降序,

易错,左右都无效,不能直接返回0。左边是降序,右边是降序,找出左边最小和右边最大,如果左边最小 < 右边最大,返回结果

3】左边求出差值,右边没有求出,说明右边是降序排列,

diff=max(lMax,右边最大元素)-lMin,右边最大元素是右边序列中第一个元素

4】左边没有求出差值,右边求出差值,左边降序,左边序列中最后一个元素最小

diff=rMax - min(rMin , 左边序列最小元素)

报错:2 1 7 4,我的结果是0,预期结果是6。

Input:[2,4,1,7,11] ,Output:9 ,Expected:10 发现漏掉了对1和7,11的比较,证明该分治算法是有问题的

{1, 7, 4, 11}, if he gives {0, 6, -3, 7},

关键:

1 leecode解法:https://discuss.leetcode.com/topic/5863/sharing-my-simple-and-clear-c-solution/16

一直记录从初始到当前元素的最小值,和最大利润(初始为0),如果当前元素 > 最小值,计算新的利润,

如果新的利润 > 当前最大利润,更新最大利润。

没想到可以通过记录一个最小元素来解决该问题,最小元素解决了需要双层循环的问题

代码:

class Solution {

public:

int maxProfit(vector<int>& prices) {

if(prices.empty())

{

return 0;

}

int size = prices.size();

int minPrice = INT_MAX;

int profitMax = 0;

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

{

if(prices.at(i) < minPrice)

{

minPrice = prices.at(i);

}

else

{

profitMax = max(profitMax , prices.at(i) - minPrice);

}

}

return profitMax;

}

};

34

Best Time to Buy and Sell Stock II

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like

(ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple

transactions at the same time (ie, you must sell the stock before you buy again).

分析:此题的意思是允许多次买入后再抛出股票。每次买入股票前必须先抛出之前买的。

输入:

5

2 4 1 7 11

4

0 6 -3 7

4

4 3 2 1

输出:

12

16

0

Leecode

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

分析:此题的意思是允许多次买入后再抛出股票。每次买入股票前必须先抛出之前买的。

举例:0 6 -3 7,可以直接先计算相邻两个元素的差值,将所有大于0的差值累加起来

代码:

class Solution {

public:

int maxProfit(vector<int>& prices) {

if(prices.empty())

{

return 0;

}

int size = prices.size();

int diff;

int maxSum = 0;

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

{

diff = prices.at(i) - prices.at(i-1);

if(diff > 0)

{

maxSum += diff;

}

}

return maxSum;

}

};

35

Word Ladder

Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:

Only one letter can be changed at a time.

Each transformed word must exist in the word list. Note that beginWord is not a transformed word.

For example,

Given:

beginWord = "hit"

endWord = "cog"

wordList = ["hot","dot","dog","lot","log","cog"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",

return its length 5.

Note:

Return 0 if there is no such transformation sequence.

All words have the same length.

All words contain only lowercase alphabetic characters.

You may assume no duplicates in the word list.

You may assume beginWord and endWord are non-empty and are not the same.

分析:这是求最短字符串长度。

输入:

hit cog 6

hot dot dog lot log cog

hit cog 5

hot dot dog lot log

输出:

5

0

Leecode

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

分析:这是求最短字符串长度。广度优先搜索用于求解最优问题。

可以使用广度优先搜索,设定每个字符串到初始字符串的距离。

根据当前遍历的字符串,找到其所有变位词,遍历变位词,如果变位词的距离已经被设置了

则跳过(说明该单词之前被访问过,不可能在一个里面出现重复的变位词),

如果没有访问过,获取当前单词距离,设置变位词的距离=当前单词距离+1

代码:

class Solution {

public:

vector<string> getOneEditWords(string& word , unordered_map<string,int>& words , unordered_map<string , vector<string> >& wordToNextWords)

{

vector<string> nextWords;

if(word.empty())

{

return nextWords;

}

if(1 == wordToNextWords.count(word))

{

return wordToNextWords[word];

}

int len = word.length();

char temp;

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

{

temp = word.at(i);

for(char ch = 'a' ; ch <= 'z' ; ch++)

{

word.at(i) = ch;

if(1 == words.count(word))

{

nextWords.push_back(word);

}

word.at(i) = temp;

}

}

wordToNextWords[word] = nextWords;

return nextWords;

}

int bfs(string beginWord, string endWord , vector<string>& wordList ,

unordered_map<string,int>& words , unordered_map<string , vector<string> >& wordToNextWords)

{

unordered_map<string ,int> strToDistance;

queue<string> queueWords;

queueWords.push(beginWord);

strToDistance[beginWord] = 0;

vector<string> nextWords;

string word;

string nextWord;

int curDistance = 0;

int size;

bool isFind = false;

while(!queueWords.empty())

{

word = queueWords.front();

queueWords.pop();

nextWords = getOneEditWords(word ,words , wordToNextWords);

if(nextWords.empty())

{

continue;

}

curDistance = strToDistance[word];

size = nextWords.size();

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

{

nextWord = nextWords.at(i);

//如果没有访问过

if(strToDistance.find(nextWord) == strToDistance.end())

{

strToDistance[nextWord] = curDistance + 1;

queueWords.push(nextWord);

if(nextWord == endWord)

{

isFind = true;

}

}

}

if(isFind)

{

break;

}

}

if(isFind)

{

return (curDistance + 2);//curDistance需要加上从当前字符串到结尾字符串的距离1,以及多1个元素

}

else

{

return 0;

}

}

int ladderLength(string beginWord, string endWord, vector<string>& wordList) {

if(beginWord.empty() || endWord.empty() || wordList.empty())

{

return 0;

}

unordered_map<string , int> words;

int size = wordList.size();

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

{

words[ wordList.at(i) ] = 1;

}

unordered_map<string , vector<string> > wordToNextWords;

int result = bfs(beginWord, endWord , wordList , words , wordToNextWords);

return result;

}

};

36

Surrounded Regions

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.

A region is captured by flipping all 'O's into 'X's in that surrounded region.

For example,

X X X X

X O O X

X X O X

X O X X

After running your function, the board should be:

X X X X

X X X X

X X X X

X O X X

输入:

4(行) 4(列)

X X X X

X O O X

X X O X

X O X X

输出:

X X X X

X X X X

X X X X

X O X X

关键

1 分析:此题实际上找到四周都是"X"的"O",并把这些"O"替换为"X"。

Leecode

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

关键

1 分析:此题实际上找到四周都是"X"的"O",并把这些"O"替换为"X"。

参考这位作者的解法:http://www.cnblogs.com/ganganloveu/p/3755191.html

关键就是从何处开始替换。观察发现在边界上的"O"都不会被替换,先将这部分"O"

转换为"#",对于最后不是"#"的"O"就全部设置为"X",然后再把"#"设置为"O"即可

后续的遍历中会对边界的邻居结点上的"O"继续递归操作

代码:

struct MyPoint

{

MyPoint(int row , int col):_row(row),_col(col){}

MyPoint(){}

int _row;

int _col;

};

class Solution {

public:

//对位置(curRow,curCol)即处于边界的元素上的"O"尝试都设置为"#"

void bfs(int curRow , int curCol , int row , int col,vector<vector<char>>& board)

{

if(curRow < 0 || curRow >= row || curCol < 0 || curCol >= col)

{

return;

}

//易错,当前元素要设置为"#"

board.at(curRow).at(curCol) = '#';

queue<MyPoint> points;

points.push(MyPoint(curRow , curCol));

MyPoint point;

while(!points.empty())

{

point = points.front();

points.pop();

//向下寻找"O"的元素

if( (point._row + 1) < row && 'O' == board.at( point._row + 1 ).at(point._col))

{

board.at( point._row + 1 ).at(point._col) = '#';

points.push(MyPoint(point._row + 1, point._col));

}

//向上

if( (point._row - 1) >= 0 && 'O' == board.at( point._row - 1 ).at(point._col) )

{

board.at(point._row - 1).at(point._col) = '#';

points.push(MyPoint(point._row - 1 , point._col));

}

//向右

if( (point._col + 1) < col && 'O' == board.at( point._row ).at(point._col + 1) )

{

board.at( point._row ).at(point._col + 1) = '#';

points.push(MyPoint( point._row , point._col + 1));

}

//向左

if( (point._col - 1) >= 0 && 'O' == board.at( point._row ).at(point._col - 1) )

{

board.at( point._row ).at(point._col - 1) = '#';

points.push(MyPoint( point._row , point._col - 1));

}

}

}

void solve(vector<vector<char>>& board) {

if(board.empty())

{

return;

}

int row = board.size();

int col = board.at(0).size();

//寻找四个边界上的"O",然后递归修改为"#"

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

{

for(int j = 0 ; j < col ; j++)

{

if(0 == i || row - 1 == i || 0 == j || col - 1 == j)

{

if('O' == board.at(i).at(j))

{

bfs(i , j , row , col , board);

}

}

}

}

//将"#"字符替换回原来的"O"

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

{

for(int j = 0 ; j < col ; j++)

{

if('#' == board.at(i).at(j))

{

board.at(i).at(j) = 'O';

}

//凡是不是"#"的"O",都是被围住的,全部修改为"X"

else if('O' == board.at(i).at(j))

{

board.at(i).at(j) = 'X';

}

}

}

}

};

37

Find Minimum in Rotated Sorted Array

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Find the minimum element.

You may assume no duplicate exists in the array.

分析:找到旋转数组中最小的元素。之前是做了找到旋转数组中某个元素是否存在。

这里假设没有重复。

输入:

7(数组元素个数)

4 5 6 7 0 1 2

9

6 7 8 0 1 2 3 4 5

7

4 5 6 0 1 2 3

3

1 2 3

2

1 2

1

1

输出:

0

0

0

1

1

1

Leecode

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

分析:找到旋转数组中最小的元素。之前是做了找到旋转数组中某个元素是否存在。

这里假设没有重复。

最小的元素:前面是最大的元素。最大的元素在升序部分中。

如果中间 > 左边,说明左边是升序,最小的元素就是在右半部分(中间不可能)。4 5 6 7 0 1 2

如果中间 < 左边,右边是升序,最小的元素应该在左半部分(中间元素也有可能),比如6 7 8 0 1 2 3 4 5

4 5 6 0 1 2 3

直到low = high,输出结果

这个应该是二分查找。

关键:

1另一种解法:https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/?tab=Solutions

左边 < 右边,升序,无旋转,直接返回最左边

否则,左边 <= 中间,左边到中间无旋转,最小值在右侧(不包含左边)

否则,右边升序,但是在左边,包含中间值

2 报错:1 2 3,如果没有逆转,发现有问题。按照之前的逻辑左边 <中间,答案在右半部分

如果左边<中间<右边,说明是升序,直接返回最左边的;

3 非升序:

左边 < 中间,左边升序,答案在右边,且包含中间值

左边 > 中间,右边升序,答案在左边,且包含中间值

左边 = 中间,说明出现low = mid,跳出,则结果在A[low]和A[high]的最小值中

代码:

class Solution {

public:

int findMin(vector<int>& nums) {

if(nums.empty())

{

return 0;

}

int low = 0;

int high = nums.size() - 1;//长度为数组值减1

int mid;

while(low < high)

{

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

//升序,返回最左边

if(nums.at(low) < nums.at(high))

{

return nums.at(low);

}

//左边小于中间,左边有序,答案在右边,不包含中间值(中间值很大), 1 2 3 0 -1

// = 说明low = mid。此时需要提高low

if(nums.at(low) <= nums.at(mid))

{

low = mid + 1;

}

//左边 > 中间 < 右边,答案在左边,包含中间值

else

{

high = mid;

}

}

return nums.at(low);

}

};

38

Find Peak Element

A peak element is an element that is greater than its neighbors.

Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.

The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.

You may imagine that num[-1] = num[n] = -∞.

For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.

click to show spoilers.

Credits:

Special thanks to @ts for adding this problem and creating all test cases.

分析:题目是为了寻找一个高峰元素,所谓高峰元素要大于两边元素,如果有多处高峰,返回其中任意的一个下标。

输入:

4(元素个数)

1 2 3 1

7

8 7 6 3 5 7 6

7

3 4 5 6 8 7 6

7

1 2 3 4 5 6 7

1

1

输出:

2

0

4

6

0

Leecode

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

分析:

所谓的高峰不就是:1】连续单调增,过了某个元素,连续单调减的元素,2】连续单调减,过了某个元素,连续单调增

题目默认所有元素不用。也可以这样认为,求出当前元素和前一个元素的斜率k1,求出当前元素和后一个元素的斜率为k2,

如果k1*k2 < 0,说明当前元素为高峰元素,由于num[-1]和num[n]已经确认

第一个元素和之前的元素的k是正值,最后一个元素和num[n]的斜率k为负值

Note:

Your solution should be in logarithmic complexity.

暴力破解,遍历一遍即可,时间复杂度为O(n)。目前需要的时间复杂度为O(logN),这种明显应该是基于二分查找的情况。

如果中间的元素大于两侧元素,直接返回;否则,应该遍历左半部分,还是右半部分

1】 左侧元素 > 中间元素,左半部分必定有峰值,向左查找

2】右侧元素 > 中间元素,右侧部分必定有峰值,向右侧查找

如果只有两个元素,

关键:

1 如果中间的元素大于两侧元素,直接返回;否则,应该遍历左半部分,还是右半部分

1】 左侧元素 > 中间元素,左半部分必定有峰值,向左查找

2】右侧元素 > 中间元素,右侧部分必定有峰值,向右侧查找

代码:

class Solution {

public:

//查找

int search(vector<int>& nums ,int low ,int high)

{

if(nums.empty() || low < 0 || high >= nums.size())

{

return 0;

}

int mid;

int size = nums.size();

bool isLeftOk = false;

bool isRightOk = false;

while(low < high)

{

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

if( mid - 1 >= 0 && mid + 1 < size)

{

//如果符合

if(nums.at(mid-1) < nums.at(mid) && nums.at(mid) > nums.at(mid+1))

{

return mid;

}

//向左查找

else if(nums.at(mid-1) > nums.at(mid))

{

high = mid - 1;//造成进位,当前元素mid不可能

}

else

{

low = mid + 1;

}

}

//没有找到

else if(mid - 1 >= 0)

{

//左边 < 当前

if(nums.at(mid-1) < nums.at(mid))

{

return mid;

}

//左边 > 当前,向左边寻找

else

{

high = mid - 1;

}

}

else if(mid + 1 < size)

{

if(nums.at(mid+1) < nums.at(mid))

{

return mid;

}

//右边 > 当前,右边寻找

else

{

low = mid + 1;

}

}

//只有一个元素,返回0

else

{

return 0;

}

}

return low;

}

};

39

Two Sum II - Input array is sorted

Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.

You may assume that each input would have exactly one solution and you may not use the same element twice.

Input: numbers={2, 7, 11, 15}, target=9

Output: index1=1, index2=2

分析:在给定升序的数组中,返回两个相加和等于指定值的下标,下标都是从1开始的,第一个下标

输入:

4(数组元素个数) 9

2 7 11 15

4 5

2 7 11 15

1 1

1

输出:

1 2

0 0

0 0

Leecode

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

代码:

class Solution {

public:

vector<int> twoSum(vector<int>& numbers, int target) {

vector<int> result;

if(numbers.empty() || 1 == numbers.size() )

{

result.push_back(0);

result.push_back(0);

return result;

}

int low = 0;

int high = numbers.size() - 1;

while(low < high)

{

if(numbers.at(low) + numbers.at(high) < target)

{

low++;

}

else if(numbers.at(low) + numbers.at(high) > target)

{

high--;

}

else

{

result.push_back(low+1);

result.push_back(high+1);

return result;

}

}

result.push_back(0);

result.push_back(0);

return result;

}

};

40

Number of Islands

Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

11110

11010

11000

00000

Answer: 1

Example 2:

11000

11000

00100

00011

Answer: 3

分析:这个实际上就是求被水(0)分割的1的块数

输入:

4(行数) 5(列数)

1 1 1 1 0

1 1 0 1 0

1 1 0 0 0

0 0 0 0 0

4 5

1 1 0 0 0

1 1 0 0 0

0 0 1 0 0

0 0 0 1 1

输出:

1

3

Leecode

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

分析:这个实际上就是求被水(0)分割的1的块数,明显可以用深度优先搜索,凡是搜索过的1都标记为访问过的,

下一次搜索的时候随机选择没有被访问过的,继续搜索,island的个数就是搜索的次数

如果用广度优先搜索,也是可以的

代码:

int g_next[][2] = {

{-1,0},//向左

{1,0},//向右

{0,1},//向上

{0,-1}//向下

};

class Solution {

public:

//深度优先搜索

void dfs(int row , int col , int rowMax , int colMax , unordered_map<string ,bool >& visited ,

vector<vector<char>>& grid)

{

string key;

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

{

int newRow = row + g_next[i][0];

int newCol = col + g_next[i][1];

//判定新的位置是否没有超出范围

if(newRow < 0 || newRow >= rowMax || newCol < 0 || newCol >= colMax )

{

continue;

}

//如果已经访问过了,跳过

stringstream stream;

stream << newRow << "#" << newCol;

key = stream.str();

if(visited.find(key) != visited.end())

{

continue;

}

//如果碰到"0"表示碰到了水,后面无法访问,跳过

if('0' == grid.at(newRow).at(newCol))

{

continue;

}

//设置当前结点已经访问

visited[key] = true;

//递归访问

dfs(newRow , newCol , rowMax , colMax , visited , grid);

}

}

int numIslands(vector<vector<char>>& grid) {

if(grid.empty())

{

return 0;

}

int row = grid.size();

int col = grid.at(0).size();

unordered_map<string , bool> visited;

string key;

int count = 0;

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

{

for(int j = 0 ; j < col ; j++)

{

//如果是陆地才访问,并且该陆地没有访问过

if('1' == grid.at(i).at(j) )

{

stringstream stream;

stream << i << "#" << j;

key = stream.str();

//如果没有访问过,才访问

if(visited.find(key) == visited.end())

{

count++;

dfs(i , j , row , col , visited , grid);

}

}

}

}

return count;

}

};

41

Minimum Size Subarray Sum

Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead.

For example, given the array [2,3,1,2,4,3] and s = 7,

the subarray [4,3] has the minimal length under the problem constraint.

click to show more practice.

More practice:

If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).

输入:

6(数组元素个数) 7(指定值)

2 3 1 2 4 3

6 20

2 3 1 2 4 3

输出:

2

0

Leecode

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

关键:

1 可以设置low和high指针开始时都指向第一个元素,

如果low~high所有元素和 < 给定值,high++

如果low~high的所有元素和>=给定值,记录high-low+1作为区间的长度,并另low++

2 预先计算第1个元素到第i个元素的和sum[i],方便后面计算

第i个元素到第j个元素的和=sum[j] - sum[i-1]

代码:

class Solution {

public:

int minSubArrayLen(int s, vector<int>& nums) {

if(nums.empty())

{

return 0;

}

int size = nums.size();

int low;

int high;

low = high = 0;

vector<long long> sum(size , 0);

sum.at(0) = nums.at(0);

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

{

sum.at(i) += sum.at(i-1) + nums.at(i);

}

if(sum.at(size - 1) < s)

{

return 0;

}

long long result;

int minLen = INT_MAX;

while(low < size && high < size)

{

if(low - 1 >= 0)

{

result = sum.at(high) - sum.at(low - 1);

}

else

{

result = sum.at(high);

}

if(result < s)

{

high++;

}

else

{

minLen = min(minLen , high - low + 1);

low++;

}

}

return minLen;

}

};

42

Contains Duplicate

Given an array of integers, find if the array contains any duplicates.

Your function should return true if any value appears at least twice in the array,

and it should return false if every element is distinct.

分析:判断数组是否含有重复元素。

输入:

3

1 2 1

3

1 2 3

输出:

true

false

Leecode

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

分析:判断数组是否含有重复元素。感觉像统计排序。

如果没有告诉你,数值范围,用位图或者统计排序会发生溢出。

这个应该是用位操作。

最简单的方法:用哈希map,来做,实际上就是链表数组

排序

关键:

1 用一个二层循环判断重复;或者先排序,再判断重复;

哈希最好

代码:

class Solution {

public:

bool containsDuplicate(vector<int>& nums) {

//为空,肯定不重复

if(nums.empty())

{

return false;

}

unordered_map<int , bool> visited ;

int size = nums.size();

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

{

if(visited.find(nums.at(i)) != visited.end())

{

return true;

}

visited[nums.at(i)] = true;

}

return false;

}

};

43

Contains Duplicate II

Given an array of integers and an integer k, find out whether there are two distinct

indices i and j in the array such that nums[i] = nums[j] and the absolute difference

between i and j is at most k.

分析:给定整数和整数k,找到是否有两个不同的下标i和j,使得nums[i]=nums[j],并且i和j的查找最多不超过k。

输入:

3 2

1 2 1

4 2

1 2 3 1

3 1

1 2 3

输出:

true

false

false

Leecode

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

分析:给定整数和整数k,找到是否有两个不同的下标i和j,使得nums[i]=nums[j],并且i和j的查找最多不超过k。

由于要记录下标信息,单纯的哈希已经需要存储一个结构体

<值,对应该值的下标集合>,考虑到下标本身需要排序,因此使用

unordered_map<int , set<int> >的结构

注意k没有说明是整数还是负数,i和j也没有说明

代码:

class Solution {

public:

bool containsNearbyDuplicate(vector<int>& nums, int k) {

if(nums.empty() || k <= 0)

{

return false;

}

int size = nums.size();

unordered_map<int , set<int> > valueToIndexs;

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

{

if(valueToIndexs.find(nums.at(i)) != valueToIndexs.end())

{

valueToIndexs[ nums.at(i) ].insert(i);

}

else

{

set<int> indexs;

indexs.insert(i);

valueToIndexs[ nums.at(i) ] = indexs;

}

}

//再次遍历一遍,看同一个值对应的下标集合中的下标之差是否 <= k

set<int> indexs;

int preIndex;

int curIndex;

for(unordered_map<int , set<int> >::iterator it = valueToIndexs.begin() ;

it != valueToIndexs.end() ; it++)

{

indexs = it->second;

//比较set中两个元素,需要获取上一个

preIndex = -1;

for(set<int>::iterator itFind = indexs.begin() ; itFind != indexs.end() ; itFind++)

{

curIndex = *itFind;

if(preIndex != -1)

{

if( curIndex - preIndex <= k)

{

return true;

}

}

preIndex = curIndex;

}

}

return false;

}

};

44

Contains Duplicate III

Given an array of integers, find out whether there are two distinct indices i and j

in the array such that the absolute difference between nums[i] and nums[j] is at most t

and the absolute difference between i and j is at most k.

分析:也就是说要寻找任意元素对应的下标i和j,满足i和j的差的绝对值<=k,两个数值的差值<=t

输入:

3(数组元素个数) 2(k) 3(t)

7 1 3

1 2 3

1

3 2 3

1 5 10

2 1 2147483647

-1 2147483647

2 2 4

-3 3

输出:

true

false

false

false

false

Leecode

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

关键:

1 被两数相减溢出坑了。面对简单的题目的加减法一定要考虑溢出

报错:Input:[-1,2147483647] 1 2147483647

Output:true

Expected:false

2还是溢出

//简单的题目:两个int数据相加减,需要先转化为long long,结果也要是long long,否则溢出

value1 = (long long)nums.at(i);

value2 = (long long)nums.at(j);

result = llabs(value1 - value2);

Input:

[2147483647,-2147483647]

1

2147483647

Output:

true

Expected:

false

3果然超时

参考这位:http://blog.csdn.net/Jeanphorn/article/details/46625729 的解法

题目是滑动窗口问题。

|nums(i) - nums(j)| <= t 【1】

|nums(i)/t - nums(j)/t| <= 1 【2】

所以nums(i)/t 属于{ nums(j)/t , nums(j)/t - 1 , nums(j)/t + 1 }

只需要以 另key = nums(i)/t 作为键,以 nums(i)作为值存储,然后当前元素nums[i]和dict[key],dict[key-1]

dict[key+1]比较即可。

另外一旦 i >= k,删除窗口之外的键值,确保下标在合理范围

//删除窗口以外的键值

if(i >= k)

{

dict.erase( nums.at(i - k) / max(1, t) );

}

}

代码:

class Solution {

public:

bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {

if(nums.empty() || k <= 0 || t < 0 || 1 == nums.size())

{

return false;

}

int size = nums.size();

unordered_map<int , long long> dict;

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

{

//注意t不能为0

int key = nums.at(i) / max(1 ,t);

if( ( dict.find(key) != dict.end() && llabs((long long)nums.at(i) - dict.at(key) ) <= t ) ||

( dict.find(key - 1) != dict.end() && llabs((long long)nums.at(i) - dict.at(key - 1) ) <= t ) ||

( dict.find(key + 1) != dict.end() && llabs((long long)nums.at(i) - dict.at(key + 1) ) <= t ) )

{

return true;

}

//找不到,需要插入键值对: nums(i) / max(1, t) ,存入的值是当前元素

dict[key] = nums.at(i) ;

//删除窗口以外的键值

if(i >= k)

{

dict.erase( nums.at(i - k) / max(1, t) );

}

}

return false;

}

};

45

First Bad Version

You are a product manager and currently leading a team to develop a new product. Unfortunately,

the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions

after a bad version are also bad.

Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one,

which causes all the following ones to be bad.

You are given an API bool isBadVersion(version) which will return whether version is bad.

Implement a function to find the first bad version. You should minimize the number of calls to the API.

分析:发现一个版本号是否是坏的版本,确保调用次数最少

被调函数要实现根据给定的版本号,找到首先是最坏的版本。最坏的版本号的特点是当前及其之后版本号都是属于坏的版本。

Leecode

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

分析:发现一个版本号是否是坏的版本,确保调用次数最少

被调函数要实现根据给定的版本号,找到首先是最坏的版本。最坏的版本号的特点是当前及其之后版本号都是属于坏的版本。

没有给出条件说明什么是坏的版本啊,仅仅一个数字没有办法判断

举例:

1 2 3 4 5 个版本中,第三个版本是起始坏的,那么3 4 5都是坏的,

应该是从后向前遍历,比如判断版本5是否是坏的,需要判断当前版本及之后版本是否都是坏的

最后一个版本是坏的,然后判断4以及之后的5是否是坏的

3,需要判断3本身是否是坏的,(既然能走到判定3,说明其之后版本一定都是坏的)

如果是第一个版本就是好的,说明没有坏的版本‘

如果第一个版本是坏的

总结:就是从后向前依次遍历,时间复杂度为O(n)

明确:出现: "好坏" 这种的时候的"坏"即为第一次出现的版本

如果假设好为0,坏为1,就是寻找类似00001111中1首次出现的位置

就是一个lower_bound的问题:寻找某数字第一次出现的位置,或者如果没有该位置,返回

的位置插入该元素仍然使得序列有序。

中间元素< 给定值:在右侧,不包含中间元素,low = mid +1

中间元素 = 给定值:在给定元素的左侧,包含中间,high = mid

中间元素 > 给定值,在给定元素的左侧,不包含中间值,high=mid-1

对于此题:

中间元素是好的

报错:超时。

Last executed input:

1926205968 versions

1167880583 is the first bad version.

关键:

1 说明:既然是整个数组,那么采用二分法,找到中间部分,中间部分如果是好的版本

中间是好的版本:在后半段,low=mid+1

中间是坏的版本:1】如果中间元素前面一个元素是好的(如果中间元素前面没有元素,就是当前元素),找到了,否则转2】

2】可能在包含中间部分的前面部分,high=mid

代码:

bool isBadVersion(int version);

class Solution {

public:

int firstBadVersion(int n) {

if(n < 1)

{

return 0;

}

int mid;

int low = 1;

int high = n;

while(low < high)

{

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

//中间元素是好的,在后面半段

if(!isBadVersion(mid))

{

low = mid + 1;

}

else

{

//如果找到了

if( 1 == mid || (!isBadVersion(mid - 1) ) )

{

return mid;

}

//如果没有找到

else

{

high = mid;

}

}

}

if(low != 1)

{

if(isBadVersion(low) && (!isBadVersion(low-1)) )

{

return low;

}

}

else

{

if(isBadVersion(low))

{

return low;

}

}

return 0;

}

};

46

Valid Perfect Square

Given a positive integer num, write a function which returns True if num is a perfect square else False.

Note: Do not use any built-in library function such as sqrt.

Example 1:

Input: 16

Returns: True

Example 2:

Input: 14

Returns: False

分析:给定一个正整数,判定它是否是一个完全平方数。不能使用内置的sqrt。

Leecode

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

47

Water and Jug Problem

You are given two jugs with capacities x and y litres. There is an infinite amount of water supply available. You need to determine whether it is possible to measure exactly z litres using these two jugs.

If z liters of water is measurable, you must have z liters of water contained within one or both buckets by the end.

Operations allowed:

Fill any of the jugs completely with water.

Empty any of the jugs.

Pour water from one jug into another till the other jug is completely full or the first jug itself is empty.

Example 1: (From the famous "Die Hard" example)

Input: x = 3, y = 5, z = 4

Output: True

Example 2:

Input: x = 2, y = 6, z = 5

Output: False

分析:此题是给定两个容量分别为x和y的杯子,问是否能够测量出容积为z的水。

Leecode

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

48

Guess Number Higher or Lower

We are playing the Guess Game. The game is as follows:

I pick a number from 1 to n. You have to guess which number I picked.

Every time you guess wrong, I'll tell you whether the number is higher or lower.

You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0):

-1 : My number is lower

1 : My number is higher

0 : Congrats! You got it!

Example:

n = 10, I pick 6.

Return 6.

分析:实际上就是猜数字游戏。给定n,求猜别人拿的是哪个数字。

Leecode

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

49

如何从数组中找出满足 a+b=c+d 的两个数对

给定一个数组,找出数组中是否有两个数对(a, b)和(c, d), 使得 a+b=c+d,其中, a、b、c和d

是不同的元素。如果有多个答案,打印任意一个即可。例如给定数组:

[3, 4, 7, 10, 20, 9, 8],可以找到两个数对(3, 8)和(4, 7),使得

3+8=4+7

Python程序员面试算法宝典

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

50

如何找出旋转数组的最小元素

把一个有序数组最开始的若干个元素搬到数组的末尾,称之为数组的旋转。

输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。例如:

数组[3,4,5,1,2]为数组[1,2,3,4,5]的一个旋转,该数组的最小值为1。

Python程序员面试算法宝典

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

51

如何求数组中两个元素的最小距离

给定一个数组,数组中含有重复元素,给定两个数字num1和num2,求这两个数字在

数组中出现的位置的最小距离。

Python程序员面试算法宝典

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

52

如何求数组中绝对值最小的数

有1个升序排列的数组,数组中可能有正数、负数或0,求数组中元素的绝对值最小的数,

例如:数组[-10, -5, -2, 7, 15, 50],该数组中绝对值最小的数是-2。

Python程序员面试算法宝典

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

53

如何寻找最多的覆盖点

坐标轴上从左到右依次的点为a[0], a[1], a[2], ..., a[n-1],

设一根木棒的长度为L,求L最多能覆盖坐标轴的几个点?

Python程序员面试算法宝典

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

54

如何求解迷宫问题

给定一个大小为N*N的迷宫,一只老鼠需要从迷宫的左上角(

对应矩阵的[0][0])走到迷宫的右下角(对应矩阵的[N-1][N-1]),

老鼠只能向两方向移动:向右或向下。在迷宫中,0表示没有路

(是死胡同),1表示有路。例如: 给定下面的迷宫:

1   0   0   0

1   1   0   1

0   1   0   0

1   1   1   1

途中标粗的路径就是一条合理的路径。

请给出算法来找到这么一条合理路径。

Python程序员面试算法宝典

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

55

如何从三个有序数组中找出它们的公共元素

给定以非递减顺序排序的三个数组,找出这三个数组中的所有公共元素。例如,

给出下面三个数组:

ar1 = [2, 5, 12, 20, 45, 85]

ar2 = [16, 19, 20, 85, 200]

ar3 = [3, 4, 15, 20, 39, 72, 85, 190]

那么这三个数组的公共元素为[20, 85]。

Python程序员面试算法宝典

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

56

如何判断两个字符串是否为换位字符串

换位字符串是指组成字符串的字符相同,但位置不同。例如:由于字符串"aaaabbc" 与 "abcbaaa"就是相同的字符所组的,因此它们是换位字符。

Python程序员面试算法宝典

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

57

如何判断两个字符串的包含关系

给定由字母组成的字符串s1和s2,其中,s2中字母的个数少于s1,如何判断s1是否包含

s2? 即出现在s2中的字符在s1中都存在。

例如s1="abcdef", s2="acf",那么s1就包含s2;

如果s1="abcdef", s2="acg",那么s1就不包含s2,因为s2

中有'g',但是s1中没有'g'

Python程序员面试算法宝典

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

58

如何判断一个字符串是否包含重复字符

判断一个字符串是否包含重复字符。例如: 'good'就包含重复字符'0',

而'abc'就不包含重复字符

Python程序员面试算法宝典

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

59

如何查找到达目标词的最短链长度

给定一个词典和两个长度相同的"开始"和"目标"的单词。

找到从开始到姆博阿的最小链的长度。如果它存在,

那么这条链中的相邻单词只有一个字符不同,

而链中的每个单词都是有效单词,即它存在于词典中。

可以假设词典中存在目标字,所有词典的长度相同。

例如:

给定一个单词词典为:

[pooN, pbcc, zamc, poIc, pbca, pbIc, poIN]

start = ToolN

target = pbca

输出结果为: 7

因为: TooN(start) - pooN - poIN - poIc - pbIc - pbcc - pbca(target)。

Python程序员面试算法宝典

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

60

如何判断一个自然数是否是某个数的平方

设计一个算法,判断给定的一个数n是否是某个数的平方,不能使用开方运算。

例如16就满足条件,因为它是4的平方,而15则不满足条件,因为不存在

一个数使得其平方的值为15.

Python程序员面试算法宝典

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

61

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

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

Python程序员面试算法宝典

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

62

黑白图像

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

如图所示,有3个八连块

输入:

6

100100

001010

000000

110000

111000

010100

输出:

3

算法竞赛入门经典

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

63

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

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

算法竞赛入门经典

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

64

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

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

算法竞赛入门经典

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

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

66

最大乘积

算法竞赛入门经典

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

67

分数拆分

算法竞赛入门经典

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

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

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

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

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

算法竞赛入门经典

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

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

77

非线性方程求根

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

2000 4 510

输出:

0.797%

算法竞赛入门经典

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

78

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

编程珠玑

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

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

算法 64式 7、搜索算法整理_第3部分_31到45题相关推荐

  1. 算法 64式 7、搜索算法整理_第1部分_1到15题

    1 算法思想 算法分类 搜索算法主要分为: 暴力搜索+剪枝,枚举,广度优先搜索,深度优先搜索,二分查找,哈希查找, A*算法,两边向中间逼近,从中间向两边扩散等 1.1枚举 枚举: 最直白的搜索方式, ...

  2. 算法 64式 7、搜索算法整理_第4部分_46到60题

    1 算法思想 算法分类 搜索算法主要分为: 暴力搜索+剪枝,枚举,广度优先搜索,深度优先搜索,二分查找,哈希查找, A*算法,两边向中间逼近,从中间向两边扩散等 1.1枚举 枚举: 最直白的搜索方式, ...

  3. 算法 64式 7、搜索算法整理_第2部分_16到30题

    1 算法思想 算法分类 搜索算法主要分为: 暴力搜索+剪枝,枚举,广度优先搜索,深度优先搜索,二分查找,哈希查找, A*算法,两边向中间逼近,从中间向两边扩散等 1.1枚举 枚举: 最直白的搜索方式, ...

  4. 算法 64式 16、字符串算法整理

    1算法思想 2 字符串系列 类别-编号 题目 来源 1 替换空格 请事先一个函数,把字符串中的每个空格替换成"%20".例如 例如 输入: We are happy. 输出: We ...

  5. 算法 64式 8、动态规划算法整理_第1部分_1到15题

    1 算法思想 动态规划 1.1含义 把问题分解成多阶段或多个子问题,顺序求解各个子问题,最后一个子问题就是初始问题的解. 概念 阶段: 问题分成的顺序的几个环节.例如最长递增子序列中每个字符就是一个阶 ...

  6. 算法 64式 8、动态规划算法整理

    1 算法思想 动态规划 1.1含义 把问题分解成多阶段或多个子问题,顺序求解各个子问题,最后一个子问题就是初始问题的解. 概念 阶段: 问题分成的顺序的几个环节.例如最长递增子序列中每个字符就是一个阶 ...

  7. 算法 64式 19、数学算法整理

    1 算法思想 2 数学系列 类别-编号 题目 遁去的一 1 特殊乘法 写个算法,对2个小于1000000000的输入,求结果. 特殊乘法举例: 123 * 45 = 1*4 + 1*5 + 2*4 + ...

  8. 算法 64式 4、回溯算法整理__第1部分_1到13题

    1算法思想 回溯 1.1含义 以深度优先方式搜索问题解的算法称为回溯法. 1.2思想 按照深度优先搜索策略,从根节点出发搜索解空间树,如果某结点不包含问题解,则逐层向祖先结点回溯:否则进入子树. 1. ...

  9. 算法 64式 17、排列组合算法整理

    1算法思想 排列组合 1.1含义 排列: 含义:从元素列表中取出指定个数的元素进行排序 公式:从n个不同元素中取出m个元素的排列个数=n!/(n-m)! 组合: 含义:从元素列表中取出指定个数的元素, ...

最新文章

  1. java多线程--死锁
  2. POJ 1986:Distance Queries(倍增求LCA)
  3. oracle执行计划没有执行索引,oracle理解执行计划之索引相关
  4. Mysql创建用户和给用户授权
  5. 步步为营-83-用户控件
  6. android Monkey test测试
  7. matlab hspice联合仿真,HSPICE TOOLBOX FOR MATLAB
  8. 安装西门子博图一直重启_西门子博图重启后继续安装没完成的程序怎么去除?...
  9. express 配置ip
  10. 木门锁孔合页综合加工机器
  11. 习题3.3投骰子的随机游戏
  12. python plt绘制多子图
  13. 简单16进制转字符串
  14. 百度文库免费下+PDF免费转,你错过了嘛?
  15. 322. 零钱兑换 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 你可以认为每
  16. 以QQ音乐为例子 解析公共接口的json数据
  17. 从Gartner 最新“客户之选”报告,看国内外RPA的差异化竞争
  18. Python 常用编程方法
  19. 掌静脉识别——无法被窃取的生物密码
  20. video标签样式铺满全屏

热门文章

  1. php laravel 教程,Laravel 入门到精通教程
  2. 小米运动数据导出并做个性化统计
  3. 安卓EROFS (Read-only file system)的解决
  4. 最简单的方法!UEFI引导+GPT分区安装win10+Ubuntu16.04双系统
  5. 从底层结构开始学习FPGA(1)----可配置逻辑块CLB(Configurable Logic Block)
  6. 【反向和同向比例运算电路】
  7. 今日头条的布局和字体适配方式
  8. 邮件标题是邮件营销的第一生产力
  9. 神经结构化学习 3 使用合成图进行训练 Neural Structured Learning - Part 3: Training with synthesized graphs
  10. 三维扫描体数据的VTK体绘制程序设计