面试题3
题目1:
牛客网链接
思路:
1.先排序,再扫描,O(nlogn)
2.哈希表,时间O(n),空间O(n)
set1
set2
这里用集合来实现这个思路
int duplicate(vector<int> nums) {
set<int> set;
int repeat = -1; //输出,如果有重复,输出重复数字,否则输出-1
for (auto num : nums) {
if (set.count(num) == 1) { //set.count只有0或1,表示是否已插入set
repeat = num;
break;
}
else
set.insert(num);
}
return repeat;
}
int main() {
//printf("hello world");
vector<int> a = { 2,3,1,0,2,5,3 };
for (auto i:a){
cout << i<<endl;
}
cout<<duplicate(a);
return 0;
}
3.标答里面的,按序扫描,扫到下标i的时候,数字为m,若等于i,就扫描下一个,若不等于i,则跟第m个数字比较,相等,就是重复数字,不等就把第i个数字和第m个数字交换,相当于一次比较找到一个正确位置
int duplicate(vector<int> nums) {
int repeat = -1;
int len = nums.size();
if (len <= 1) { //增加一个对长度0或者1的处理
return repeat;
}
for (int i = 0; i < len; ++i) {
while (nums[i] != i) { //这里注意可以用nums[i]赋值一个m
//这里的while要注意,不能用if,因为一次交换以后i的位置数字不等于i,就要继续在i的位置判断
//每次只是把m换到正确的位置上
//这里不会无限循环,因为前提条件长度为n的数组,所有数字都在0——n-1,若没有重复,
//则换到最后i的位置必能出现i,若有重复,必能交换出重复结果退出循环
if (nums[i] == nums[nums[i]]) {
repeat = nums[i];
break;
}
swap(nums[i], nums[nums[i]]);
//这里直接用了swap
}
}
return repeat;
}
int main() {
//printf("hello world");
vector<int> a = { 2,3,1,0,2,5,3 };
//vector<int> a = {1};
for (auto i:a){
cout << i<<endl;
}
cout<<duplicate(a);
return 0;
}
面试题4
牛客网链接
为什么从右上角开始比较:
为了每次比较完,能缩小排查范围,要找的数比右上角小,排除最右列,比右上角大,排除第一行,左上角比较就做不到。
注意:遇到此类问题,先做个具体例子,比如4x4的矩阵,再进行分析。
bool Find(int target, vector<vector<int> > array) {
bool found = false;
int rows = array.size(); //总的行数
int cols = array[0].size(); //总的列数
int row = 0,col = cols-1; //比较的数字位置
if(rows>0 && cols>0){
while(row < rows && col >= 0 ){
if(target == array[row][col] ){
found = true;
break;
}
if(target > array[row][col]){
row += 1;
}
else{
col -= 1;
}
}
}
return found;
}
面试题5
牛客网链接
思路1:
顺序遍历替换,直接开辟一块新的空间,把非空格复制过来,空格换成"%20"连接字符串
时间复杂度O(n),空间O(n),如果要原地替换,就得往后移,时间复杂度为O(n^2),空间O(1)
string replaceSpace(string s) {
string s1;
for (auto i : s) {
if (i != ' ') {
s1 += i;
}
else {
s1 = s1 + "%20";
//这里,'%20'会导致We0Are0Happy
//这个结果说明直接用+可以连接string
}
}
return s1;
}
int main() {
string s = "We Are Happy";
int len = s.length();//长度没包括'/0',注意字符串长度是.length()
cout << len << endl;
cout << replaceSpace(s) << endl;
return 0;
}
思路2:
剑指上的思路,从后往前逐个字符替换,这个思路是用字符数组的形式处理这个问题,相较而言,这个思路比较值得学习。
代码略,意义不大。
面试题6
牛客网链接
思路:直接用栈,存储里面数据,遍历完弹出即可。
vector<int> printListFromTailToHead(ListNode* head) {
ListNode* ptr = head;
stack<int> s;
vector<int> v;
while (ptr != nullptr) {
s.push(ptr->val);
ptr = ptr->next;
}
while (!s.empty()) {
v.push_back(s.top());
s.pop();
}
return v;
}
可以记一下这个建立链表节点的代码
typedef struct ListNode {
int val;
struct ListNode* next;
ListNode(int x) :
val(x), next(NULL) {
}
};
面试题7
牛客网链接
要掌握二叉树3种遍历的6种写法,加上层序。
class Solution {
public:
vector<int> p, v;
TreeNode* build(int pl, int pr, int vl, int vr){
if(pl > pr)
//注意这个是pl>pr不是>=,等于的情况是叶子节点
return nullptr;
TreeNode* root = new TreeNode(p[pl]);
int index=vl;//中序序列里面根节点的下标
while (index <= vr && p[pl] != v[index]){
++index;
}
int len = index-vl;
root->left = build(pl+1,pl+len,vl,index-1);
//左子树在前序和中序里面的头尾下标
root->right = build(pl+len+1,pr,index+1,vr);
//右子树在前序和中序里面的头尾下标
return root;
}
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.size() == 0 || vin.size() == 0)
return nullptr;
p = pre, v = vin;
return build(0, pre.size()-1, 0, vin.size()-1);
}
};
面试题8
牛客网链接
参考题解
思路1:
1.找根节点
2.中序建立二叉树,按遍历顺序将节点存进vector
3.扫描vector,取出下一个节点
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
void In_order(TreeLinkNode* root, vector<TreeLinkNode*> &v){
//递归中序建立二叉树,要记住
if(!root)
return;
In_order(root->left, v);
v.push_back(root);
In_order(root->right, v);
}
TreeLinkNode* GetNext(TreeLinkNode* pNode) {
//找根节点
TreeLinkNode* root = pNode;
while (root->next != nullptr){
root=root->next;
}
vector<TreeLinkNode*> v;
In_order(root, v);
int len = v.size();
for(int i=0; i<len; ++i){
if(v[i]==pNode && i+1<len){
return v[i+1];
}
}
return nullptr;
}
};
思路2:
有右子->右子下面最左的
无右子->有父节点->是父节点的左子节点->父节点
------------------------->是父节点的右子节点->向上追溯,若有节点是父节点的左子节点,则是该父节点
---------->无父节点->nullptr
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode) {
if(pNode->right){
pNode=pNode->right;
while(pNode->left){
pNode=pNode->left;
}
return pNode;
}
while(pNode->next){
if(pNode == pNode->next->left){
return pNode->next;
}
pNode=pNode->next;
}
return nullptr;
}
};
面试题9
牛客网链接
思路:
画图1,2,3,4为例就可,push直接到s1,pop的时候,如果s2空,就把s1退栈反向存进s2,如果s2不空,就直接取s2栈顶并退栈。
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
if(stack2.empty()){
while(!stack1.empty()){
stack2.push(stack1.top());
stack1.pop();
}
}
int ans = stack2.top();
stack2.pop();
return ans;
}
private:
stack<int> stack1;
stack<int> stack2;
};
这篇博客探讨了多种算法面试题,涉及排序、哈希表和链表的操作。首先,介绍了如何在O(nlogn)和O(n)的时间复杂度内查找数组中的重复元素,分别使用排序和哈希表的方法。接着,阐述了从右上角开始遍历矩阵以查找目标值的策略,以及如何高效地替换字符串中的空格。此外,还讲解了如何通过前序和中序遍历来重建二叉树,以及如何在双向链表中找到下一个节点。最后,提出了一种双栈解决方案,使得在保持元素顺序的同时实现先进后出的弹出操作。
1468

被折叠的 条评论
为什么被折叠?



