搜索练习题及参考代码
01搜索插入位置
问题描述
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O ( l o g n ) O(log n) O(logn) 的算法。
- 1 ≤ n u m s . l e n g t h ≤ 1 0 4 1 \le nums.length \le 10^4 1≤nums.length≤104
- − 1 0 4 ≤ n u m s [ i ] ≤ 1 0 4 -10^4 \le nums[i] \le 10^4 −104≤nums[i]≤104
- nums 为 无重复元素 的 升序 排列数组
- − 1 0 4 ≤ t a r g e t ≤ 1 0 4 -10^4 \le target \le 10^4 −104≤target≤104
输入描述
第一行输入一个整数n
表示数组的长度
第二行是n
个由空格分割的整数,代表数组nums
第三行是一个整数target
代表目标值
输出描述
输出一个整数代表目标值的索引或它将被插入的位置
输入样例1
4
1 3 5 6
5
输出样例1
2
输入样例2
4
1 3 5 6
2
输出样例2
1
参考代码
#include<iostream>
#include<vector>
using namespace std;
int main(){
int n, target;
cin>>n;
vector<int> nums(n);
for(int i=0;i<n;i++){
cin>>nums[i];
}
cin>>target;
int l=0, r=n;
while(l < r) {
int m = l + (r - l) / 2;
if (nums[m] == target) {
cout<<m<<endl;
return 0;
} else if (nums[m] < target) {
l = m + 1;
} else if (nums[m] > target) {
r = m ;
}
}
cout<<r<<endl;
return 0;
}
02求平方根
问题描述
给你一个非负整数 x
,计算并返回 x
的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5)
或者 x ** 0.5
。
- 0 ≤ x ≤ 2 31 − 1 0 \le x \le 2^{31} - 1 0≤x≤231−1
输入描述
第一行输入一个整数x
输出描述
输出一个整数代表x
的平方根
输入样例
8
输出样例
2
参考代码
#include<iostream>
using namespace std;
int main(){
int x;
cin>>x;
int l=0, r=x, ans=-1;
while(l <= r) {
int m = l + (r - l) / 2;
if ((long long)m*m <= x) {
ans = m;
l = m + 1;
} else{
r = m - 1;
}
}
cout<<ans<<endl;
return 0;
}
03左叶子之和
问题描述
给定二叉树,返回所有左叶子之和。
输入描述
第一行输入一个整数n
表示数组长度
第二行 n
个用空格分隔开的整数代表顺序存储的树节点的值,其中 -1
代表没有节点
- 节点数在
[1, 1000]
范围内 0 <= Node.val <= 1000
输出描述
输出一个整数
输入样例
7
3 9 20 -1 -1 15 7
输出样例
24
参考代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int main(){
int n;
cin>>n;
vector<int> tree(n);
for(int i=0;i<n;i++){
cin>>tree[i];
}
int ans = 0;
queue<int> nodes;
nodes.push(0);
while(!nodes.empty()){
int front = nodes.front();
nodes.pop();
int l = front*2+1;
int r = front*2+2;
if((tree[l]==-1 || l>=n) && (tree[r]==-1 || r>=n) && front%2==1){
ans += tree[front];
continue;
}
if(tree[l]!=-1 && l<n){
nodes.push(l);
}
if(tree[r]!=-1 && r<n){
nodes.push(r);
}
}
cout<<ans<<endl;
return 0;
}
04二叉树的前序遍历
问题描述
给定二叉树,返回它节点值的 前序 遍历。
输入描述
第一行输入一个整数n
表示数组长度
第二行 n
个用空格分隔开的整数代表顺序存储的树节点的值,其中 -1
代表没有节点
- 节点数在
[1, 100]
范围内 0 <= Node.val <= 100
输出描述
输出节点值的前序遍历
输入样例
7
3 9 20 -1 -1 15 7
输出样例
3 9 20 15 7
参考代码
#include<iostream>
#include<vector>
using namespace std;
int n;
vector<int> tree;
vector<int> ans;
void dfs(int index){
if(index >= n || tree[index]==-1) return;
ans.push_back(tree[index]);
int l = index*2+1;
int r = index*2+2;
dfs(l);
dfs(r);
}
int main(){
cin>>n;
tree = vector<int>(n);
for(int i=0;i<n;i++){
cin>>tree[i];
}
dfs(0);
for(int i=0;i<ans.size()-1;i++){
cout<<ans[i]<<" ";
}
cout<<ans[ans.size()-1]<<endl;
return 0;
}
05颜色填充
问题描述
请你实现许多图片编辑软件都支持的「颜色填充」功能。
待填充的图像用二维数组 image
表示,元素为初始颜色值。初始坐标点的行坐标为 sr
列坐标为 sc
。需要填充的新颜色为 newColor
。
「周围区域」是指颜色相同且在上、下、左、右四个方向上存在相连情况的若干元素。
请用新颜色填充初始坐标点的周围区域,并返回填充后的图像。
- 边长在
[1, 50]
范围内 - 颜色在
[0, 65535]
范围内 - 初始坐标点
(sr,sc)
满足0 <= sr < image.length
和0 <= sc < image[0].length
输入描述
第一行输入一个整数n
表示图片的边长(图片为正方形)
之后n
行,每行 n
个用空格分隔开的整数代表图像中的颜色
最后一行三个用空格隔开的整数,分别表示 sr
、 sc
和 newColor
输出描述
n
行 n
列表示修改后的图像
输入样例
3
1 1 1
1 1 0
1 0 1
1 1 2
输出样例
2 2 2
2 2 0
2 0 1
参考代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int main(){
int n, sx, sy, newColor, color;
cin>>n;
vector<vector<int>> image(n, vector<int>(n));
vector<vector<int>> visited(n, vector<int>(n));
vector<vector<int>> move = { {1,0}, {-1,0}, {0,1}, {0,-1} };
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>image[i][j];
}
}
cin>>sx>>sy>>newColor;
color = image[sx][sy];
queue<int> xq;
queue<int> yq;
xq.push(sx);
yq.push(sy);
while(!xq.empty()){
int x = xq.front();
int y = yq.front();
xq.pop();
yq.pop();
for(int i=0;i<move.size();i++){
int tx = x + move[i][0];
int ty = y + move[i][1];
if( tx>=0 && tx<n && ty>=0 && ty<n && image[tx][ty]==color && visited[tx][ty]!=1 ){
image[tx][ty] = newColor;
visited[tx][ty] = 1;
xq.push(tx);
yq.push(ty);
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n-1;j++){
cout<<image[i][j]<<" ";
}
cout<<image[i][n-1]<<endl;
}
return 0;
}
06走迷宫
问题描述
下图给出了一个迷宫的平面图,其中标记 1
的为障碍,标记为 0
的为可以通行的地方。
010000
000100
001001
110000
迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置向它的上、下、左、右四个方向行走,我们用U、D、L、R分别表示向下、向上、向左、向右行走。
请找出一种通过迷宫的方式,其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。(注:在字典序中D<L<R<U)
- 边长在
[1, 50]
范围内
输入描述
第一行输入两个整数h、w
表示迷宫的的高和宽
之后h
行,每行 w
个连续字符代表迷宫的标记
输出描述
以DLRU表示的通过迷宫的一串字符串
输入样例
4 6
010000
000100
001001
110000
输出样例
DRRURRDDDR
参考代码
#include<iostream>
#include<string>
#include<vector>
#include<queue>
using namespace std;
const int ax[4]={1,0,0,-1};
const int ay[4]={0,-1,1,0};
const char dir[4]={'D','L','R','U'};
int h, w;
vector<vector<int>> maze;
struct point {
int x,y;
string ans;
point(int a,int b,string c):x(a),y(b),ans(c){}
};
bool judge(int x,int y) {
if(x>=0&&x<h&&y>=0&&y<w&&!maze[x][y])
return true;
return false;
}
void bfs() {
queue<point>ans;
ans.push(point(0,0,""));
maze[0][0]=1;
while(!ans.empty()) {
point temp=ans.front();
ans.pop();
if(temp.x==h-1&&temp.y==w-1) {
cout<<temp.ans<<endl;
return ;
}
for(int i=0;i<4;i++) {
int tempx=temp.x+ax[i];
int tempy=temp.y+ay[i];
if(judge(tempx,tempy)) {
maze[tempx][tempy]=1;
ans.push(point(tempx,tempy,temp.ans+dir[i]));
}
}
}
}
int main() {
cin>>h>>w;
maze = vector<vector<int>>(h, vector<int>(w));
for(int i=0;i<h;i++)
for(int j=0;j<w;j++) {
char t;
cin>>t;
maze[i][j]=t-'0';
}
bfs();
return 0;
}
07数独
问题描述
给你一个未完成的数独,请找到其正确答案。
- 数独答案唯一
输入描述
输入9行
每行 9个连续字符代表数独的数字,数字为0表示该格还未填入数字。
输出描述
将完成的数独逐行输出
输入样例
000000010
060030008
428000007
601004000
030700120
580000000
000003054
005801900
700000000
输出样例
359487612
167932548
428156397
671524839
934768125
582319476
816293754
245871963
793645281
参考代码
#include<iostream>
#include<string>
#include<vector>
using namespace std;
bool isValid(int row, int col, char val, vector<vector<char>>& board) {
for (int i = 0; i < 9; i++) { // 判断行里是否重复
if (board[row][i] == val) {
return false;
}
}
for (int j = 0; j < 9; j++) { // 判断列里是否重复
if (board[j][col] == val) {
return false;
}
}
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复
for (int j = startCol; j < startCol + 3; j++) {
if (board[i][j] == val ) {
return false;
}
}
}
return true;
}
bool backtrack(vector<vector<char>>& board) {
for (int i = 0; i < board.size(); i++) { // 遍历行
for (int j = 0; j < board[0].size(); j++) { // 遍历列
if (board[i][j] != '0') continue;
for (char k = '1'; k <= '9'; k++) { // (i, j) 这个位置放k是否合适
if (isValid(i, j, k, board)) {
board[i][j] = k; // 放置k
if (backtrack(board)) return true; // 如果找到合适一组立刻返回
board[i][j] = '0'; // 回溯,撤销k
}
}
return false;
}
}
return true;
}
int main(){
vector<vector<char>> board(9, vector<char>(9));
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
cin>>board[i][j];
}
}
backtrack(board);
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
cout<<board[i][j];
}
cout<<endl;
}
return 0;
}
08N皇后问题
问题描述
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案的数量。
- n<13
输入描述
输入一个整数 n
输出描述
输出一个整数
输入样例
4
输出样例
2
参考代码
#include<iostream>
#include<vector>
using namespace std;
int c, n;
vector<int> location;
bool check(int i,int j)
{
for(int k=0;k<location.size();k++)
{
int x=k;
int y=location[k];
if(x==i||y==j) return false;
if(x-i+j-y==0 || x-i-j+y==0) return false;
}
return true;
}
void backtrack(int i)
{
if(i==n) c++;
for (int j=0;j<n;j++)
{
if(check(i,j))
{
location.push_back(j);
backtrack(i+1);
location.pop_back();
}
}
}
int main()
{
cin>>n;
c =0;
backtrack(0);
cout<<c;
}
输出样例
2
参考代码
#include<iostream>
#include<vector>
using namespace std;
int c, n;
vector<int> location;
bool check(int i,int j)
{
for(int k=0;k<location.size();k++)
{
int x=k;
int y=location[k];
if(x==i||y==j) return false;
if(x-i+j-y==0 || x-i-j+y==0) return false;
}
return true;
}
void backtrack(int i)
{
if(i==n) c++;
for (int j=0;j<n;j++)
{
if(check(i,j))
{
location.push_back(j);
backtrack(i+1);
location.pop_back();
}
}
}
int main()
{
cin>>n;
c =0;
backtrack(0);
cout<<c;
}