给秋招加点料——Hot15道高频算法面试题!
Posted _Rikka_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了给秋招加点料——Hot15道高频算法面试题!相关的知识,希望对你有一定的参考价值。
目录
1.链表篇
反转链表
难度:easy
考察次数:189
题目描述
输入一个链表,反转链表后,输出新链表的表头。
思路:创建三个指针,一个表示前一个结点pre,一个表示当前节点cur,一个表示后一个节点next。循环next=cur->next,cur->next=pre,pre=cur,cur=next,直到当前节点为NULL。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode* cur=pHead,*pre=NULL,*next;
while(cur!=NULL)
{
next=cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
return pre;}
};
判断链表中是否有环
难度:easy
考察次数:120
题目描述
判断给定的链表中是否有环。如果有环则返回true,否则返回false。
你能给出空间复杂度的解法么?
思路:采用快慢指针解决,慢指针每次向前移动一步,快指针每次向前移动2步,如果链表中有环,快慢指针一定会相遇,注意一下溢出,判断快指针的下一步是不是NULL,如果为NULL则fast->next->next就溢出了。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *fast=head,*cur=head;
while(fast!=NULL&&fast->next!=NULL)
{
cur=cur->next;
fast=fast->next->next;
if(cur==fast)return true;
}
return false;
}
};
合并有序链表
难度: middle
考察次数:57
题目描述
将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的,且合并后新链表依然有序。
思路:先确定表头,创建一个cur表示当前指针,之后比较两个链表表头节点,每次都让cur->next=较小表头的指针,并让该指针移动到其next,直到某链表为空,将剩余链表全部接到cur后面即可。
AC code
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param l1 ListNode类
* @param l2 ListNode类
* @return ListNode类
*/
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
// write code here
ListNode* cur,*head;
if(l1==NULL)return l2;
else if(l2==NULL)return l1;
else if(l1->val<=l2->val){cur=l1;l1=l1->next;}
else {cur=l2;l2=l2->next;}
head=cur;
while(!(l1==NULL&&l2==NULL))
{
if(l2==NULL){cur->next=l1;l1=l1->next;}
else if(l1==NULL) {cur->next=l2;l2=l2->next;}
else if(l1->val<=l2->val){cur->next=l1;l1=l1->next;}
else {cur->next=l2;l2=l2->next;}
cur=cur->next;
}
return head;
}
};
2.动态规划篇
跳台阶
难度: easy
考察次数: 55
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
思路: d[i]表示从0到第i个台阶总共的方案数。转移方程:dp[i]=dp[i-1]+dp[i-2],因为当前台阶可以由前两级台阶走到,初始dp[0]=1,dp[1]=1
。
AC code
class Solution {
public:
int jumpFloor(int number) {
int dp[10000];
dp[1]=1,dp[0]=1;
for(int i=2;i<=number;i++)
{
dp[i]=dp[i-1]+dp[i-2];
}
return dp[number];
}
};
子数组的最大累加和
难度:easy
考察次数:52
题目描述
给定一个数组arr,返回子数组的最大累加和
例如,arr = [1, -2, 3, 5, -2, 6, -1],所有子数组中,[3, 5, -2, 6]可以累加出最大的和12,所以返回12.
题目保证没有全为负数的数据
[要求]
时间复杂度为O(n)O(n)O(n),空间复杂度为O(1)O(1)O(1)
思路:dp[i]为以第i个元素为结尾的最大累加和,状态转移方程:dp[i]=max(dp[i-1]+arr[i],arr[i]),从这可看出其实dp[i]只与dp[i-1]有关,所以对于dp的存储只需要一个空间,每次更新当前dp即可dp(相当于更新后的dp[i])=max(dp(相当于dp[i-1])+arr[i],arr[i])。
AC code
class Solution {
public:
/**
* max sum of the subarray
* @param arr int整型vector the array
* @return int整型
*/
int dp=0,ans=0;
int maxsumofSubarray(vector<int>& arr) {
// write code here
for(int i=0;i<arr.size();i++)
{
dp=max(dp,0)+arr[i];
ans=max(ans,dp);
}
return ans;
}
};
求路径
难度:easy
考察次数:15
题目描述
一个机器人在m×n大小的地图的左上角(起点)。
机器人每次向下或向右移动。机器人要到达地图的右下角(终点)。
可以有多少种不同的路径从起点走到终点?
备注:m和n小于等于100,并保证计算结果在int范围内
思路: dp[i][j]表示走到 位置 i,j 的路径数,状态转移方程 dp[i][j]=dp[i-1][j]+dp[i][j-1] ,注意边界的处理情况。
AC code
class Solution {
public:
/**
*
* @param m int整型
* @param n int整型
* @return int整型
*/
long long dp[105][105];
long long dfs(int x,int y,int n,int m)
{
if(dp[x][y])return dp[x][y];
if(x<1||x>n||y<1||y>m)return 0;
return dp[x][y]=dfs(x-1,y,n,m)+dfs(x,y-1,n,m);
}
long long uniquePaths(int m, int n) {
// write code here
dp[1][1]=1;
return dfs(m,n,m,n);
}
};
最长公共子串
难度:middle
考察次数:52
题目描述
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
思路: dp[i][j]代表str1串第以第i个字符结尾和str2串的公共串长度。状态转移方程:如果:str1[i]==str2[j],dp[i][j]=dp[i-1][j-1]+1,如果str1[i]!=str2[j],dp[i][j]=0。然后题目求的是最长串,那我们只需记录哪时dp[i][j]最大,最长公共串即为此时的i向前取dp[i][j]长度。
AC code
class Solution {
public:
/**
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
int dp[5005][5005];
int ans=0;
string LCS(string str1, string str2) {
string str;
for (int i = 0;i < str1.size();i++)
{
for (int j = 0;j < str2.size();j++)
{
if (str1[i] == str2[j])
{
if (i - 1 >= 0 && j - 1 >= 0)
{
dp[i][j] = dp[i - 1][j - 1] + 1;
if (dp[i - 1][j - 1] + 1 > ans)
{
str = str1.substr(i - dp[i - 1][j - 1], dp[i - 1][j - 1] + 1);
ans = max(dp[i - 1][j - 1] + 1, ans);
}
}
else {[`
dp[i][j] = 1;
if (1 >= ans) { ans = 1;str = str1[i]; }
}
}
else dp[i][j] = 0;
}
}
return str;
}
};
3.树篇
两个节点最近公共祖先
难度:middle
考察次数:32
题目描述
给定一棵二叉树以及这棵树上的两个节点 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。
思路: 用一个map[i]记录以当前节点i为根,如果子树有一个所要求的节点则map[i]=1,两个则map[i]=2,从根节点深度优先搜索,第一个map为二的节点即为最近的公共祖先。
AC code
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param root TreeNode类
* @param o1 int整型
* @param o2 int整型
* @return int整型
*/
map<int, int> ma;
int dfs(TreeNode* n,int a,int b)
{
if (n == NULL)return 0;
if (n->val == a )ma[a]++;
if (n->val == b )ma[b]++;
int g = ma[n->val] + dfs(n->left, a, b) + dfs(n->right, a, b);
if (f==-1 && g >= 2)
{
f = n->val;
}
return g;
}
int f = -1;
int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
dfs(root, o1, o2);
return f;
}
};
实现二叉树先中后序排列
难度:middle
考察次数:97
题目描述
分别按照二叉树先序,中序和后序打印所有的节点。
思路: 深度优先搜索,先序遍历即每到一个节点优先访问当前的节点值,后续遍历最后访问当前节点值,中序遍历先访问左节点再访问当前节点值最后访问右节点。
AC code
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
#include<stack>
class Solution {
public:
/**
* @param root TreeNode类 the root of binary tree
* @return int整型vector<vector<>>
*/
int lst[4][100005];
int g[4];
void preorder(TreeNode *p)
{
if(p==NULL)return;
lst[1][++g[1]]=p->val;
preorder(p->left);
preorder(p->right);
}
void pastorder(TreeNode *p)
{
if(p==NULL)return;
pastorder(p->left);
pastorder(p->right);
lst[3][++g[3]]=p->val;
}
void inOrder(TreeNode* p)
{
if(p==NULL)return;
inOrder(p->left);
lst[2][++g[2]]=p->val;
inOrder(p->right);
}
vector<vector<int> > threeOrders(TreeNode* root) {
// write code here
g[1]=0,g[2]=0,g[3]=0;
preorder(root);
inOrder(root);
pastorder(root);
vector<vector<int>> ans;
for(int i=1;i<=3;i++)
{
vector<int> vec;
for(int j=1;j<=g[i];j++)vec.push_back(lst[i][j]);
ans.push_back(vec);
}
return ans;
}
};
二叉树之字形遍历
难度:middle
考察次数:37
题目描述
给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)
例如:
给定的二叉树是{3,9,20,#,#,15,7},
该二叉树之字形层序遍历的结果是
[
[3],
[20,9],
[15,7]
]
思路: 每次遍历一层的节点保存到一个列表中,然后下一层要从相反方向遍历,那么只需从当前层的后面往前面遍历子节点即可(每个下一层都是前一层的相反方向就实现了之字形遍历了),还要注意每次到新的一层要改变一下遍历方向,比如这层先遍历左节点再右节点,下层先右节点再左节点。
AC code
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param root TreeNode类
* @return int整型vector<vector<>>
*/
vector<vector<int> > zigzagLevelOrder(TreeNode* root) {
// write code here
vector<vector<int>> ans;
if(root==NULL)return ans;
vector<TreeNode*> vec,t;
vector<int> lst{root->val};
ans.push_back(lst);
vec.push_back(root);
int f=1;
while(!vec.empty())
{
t.clear();
for(int i=vec.size()-1;i>=0;i--)
{
if(f==1)
{
if(vec[i]->right!=NULL)t.push_back(vec[i]->right);
if(vec[i]->left!=NULL)t.push_back(vec[i]->left);
}
else
{
if(vec[i]->left!=NULL)t.push_back(vec[i]->left);
if(vec[i]->right!=NULL)t.push_back(vec[i]->right);
}
}
vec=t;
vector<int> tt;
for(int i=0;i<vec.以上是关于给秋招加点料——Hot15道高频算法面试题!的主要内容,如果未能解决你的问题,请参考以下文章
秋招冲刺应届生JAVA岗-每日5道高频面试题Day6- 基础篇
秋招冲刺-每日打卡应届生JAVA岗-每日5道高频面试题Day2-基础篇
秋招冲刺应届生JAVA岗-每日5道高频面试题Day7- 集合篇
秋招冲刺-每日打卡应届生JAVA岗-每日5道高频面试题Day3-基础篇