【25届秋招备战C++】超高频面试手撕代码题

LRU

链接: leetcode

题目要求:实现一个满足LRU(最近最少使用)缓存约束的数据结构类。

解题思路:
数据结构的选择:时间复杂度O(1)的插入与查询,优先考虑哈希表的查询,队列和栈的插入,而插入要按时间顺序,因为超出范围后要删除时间最久的,故而选用双端队列,即容器内元素以哈希表结构存储的双端队列,这里用list<pair<int,int>>的结构实现哈希匹配。

class LRUCache{
public:
	LRUCache(int capacity):capsize(capacity){}
	int get(int key){
		if(map[key]==map.end())return -1;
		auto key_value=*map[key];
		cache.erase(map[key]);
		cache.push_front(key_value);
		map[key]=cache.begin();
		return key_value.second();
	}
	void put(int key,int value)
	{
		if(map[key]==map.end()){
			if(cache.size()==capsize)
			{
				map.erase(cache.back().first);
				cache.pop_back();
			}
			else{
				cache.erase(map[key]);
			}
			cache.push_front({key,value});
			map[key]=cache.begin();
		}
	}
private:
	list<pair<int,int>> cache;
	unordered_map<int,list<pair<int,int>>::iterator> map;
	int capsize;
}

判断链表是否有环

链接:leetcode

题目要求:判断链表是否有环,有环返回入环的第一个节点,否则返回null

解题思路:双指针,若快慢指针能相遇在,则说明有环,且当前位置即为所求。
快指针和慢指针同时开始,每次快指针走两步,慢指针走一步,设共a+b个节点,且第a+1个节点即为环的入口,那么快慢指针第一次相遇时二者必然差n个环,即快指针走的步数f-慢指针走的步数s=n*b, f − s = n b f-s=nb fs=nb,且此时 f = 2 s f=2s f=2s,再设入口节点为k,那么 k = a + n b k=a+nb k=a+nb,如果此时快指针从0开始,与慢指针同步走,每次都只走一步,那么当快指针走到入口处时,慢指针也刚好走到,二者第二次相遇,返回慢指针此时指向的节点即得所求。

//注意链表定义,ACM模式下需要对链表进行定义
struct ListNode{
	int val;
	ListNode *next;
	ListNode(int x):val(x),next(null){}
}
class Solution{
public:
	ListNode* detectCycle(ListNode* node)
	{
		ListNode* fast=node;
		ListNode* slow=node;
		while(fast && fast->next)
		{
			fast=fast->next->next;
			slow=slow->next;
			if(fast==slow)break;
		}
		if(!fast || !fast->next) return nullptr;
		
		fast=node;
		while(fast!=slow)
		{
			fast=fast->next;
			slow=slow->next;
		}
		return slow;	
	}	
}

反转链表

链接: leetcode

题目描述:给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。

解题思路:类似于元素交换,新建一个链表存储当前链表下一节点,更改当前链表的下一节点为上一节点(初始为空指针),给上一节点赋值为当前节点,当前节点接着赋值为暂存的下一节点

struct ListNode{
	int val;
	ListNode* next;
	ListNode(int x):val(x),next(nullptr){}
	ListNode():val(0)next(nullptr){};
	ListNode(int x,ListNode* next):val(x),next(next){}
}
class Solution{
public:
	ListNode* reverseList(ListNode* head)
	{
		ListNode* cur=head,*pre=nullptr;
		while(cur!=nullptr)
		{
			ListNode* tmp=cur->next;
			cur->next=pre;
			pre=cur;
			cur=tmp;
		}
		return pre;
	}
}

合并两个有序链表

链接: leetcode

题目描述:合并两个有序链表并按升序返回

解题思路:引入第三个链表实现即可,同时为了方便处理新链表的头节点,引入了一个cur指针初始化指向一个新的链表节点,节点值为0,避免头节点处理。

/*struct ListNode{
	int val;
	ListNode* next;
	ListNode(int x):val(x),next(nullptr){}
	ListNode():val(0),next(nullptr){};
	ListNode(int x,ListNode* next):val(x),next(next){}
}*/
class Solution{
public:
	ListNode *trainningPlan(ListNode*l1,ListNode* l2)
	{
		ListNode* cur=new ListNode(0);
		ListNode* pre=cur;
		while(l1!=nullptr && l2!=nullptr{
			if(l1->val>=l2->val)
			{
				pre->next=l2;
				l2=l2->next;
			}
			else{
				pre->next=l1;
				l1=l1->next;			
			}
			pre->next=l1!=nullptr:l1:l2;
			return cur->next;
		}
	} 
	
}

二叉树的遍历(前中后序)

链接: leetcode-中
leetcode-前
leetcode-后

struct TreeNode{
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode()val(0),left(nullptr),right(nullptr){}
	TreeNode(int x):val(x),left(nullptr),right(nullptr){}
	TreeNode(int x,TreeNode* left,TreeNode* right):val(x),left(left),right(right){}
}

class Solution{
public//中
	void traversal(TreeNode* cur,vector<int>& vec)
	{
		if(root==null) return nullptr;
		traversal(cur->left,vec);
		vec.push_back(cur->val);
		traversal(cur->right,vec);
	}
	vector<int> inorderTraversal(TreeNode* root)
	{
		vector<int> res;
		traversal(root,res);
		return res;
	}
//前
class Solution {
public:
    void preorder(TreeNode *root, vector<int> &res) {
        if (root == nullptr) {
            return;
        }
        res.push_back(root->val);
        preorder(root->left, res);
        preorder(root->right, res);
    }

    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;
        preorder(root, res);
        return res;
    }
};
//后
class Solution {
public:
    void postorder(TreeNode *root, vector<int> &res) {
        if (root == nullptr) {
            return;
        }
        postorder(root->left, res);
        postorder(root->right, res);
        res.push_back(root->val);
    }

    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        postorder(root, res);
        return res;
    }
};

合并有序数组

链接: leetcode

题目描述:合并两个非递减顺序排列的整数数组,结果按非递减顺序排列并原地保存在其中一个数组中,

解题思路:逆向双指针,从后向前填充可避免覆盖


class Solution{
publicvoid merge(vector<int>& nums1,int m,vector<int>& nums2,int n)
	{
		int size1=m-1,size2=n-1,sizea=m+n-1;
		while(size1>=0 && size2>=0)
		{
			nums[k--]= nums1[size1]>nums2[size2]?nums1[size1]:nums2[size2];
		}
		while(i>=0)
		{
			nums[k--]=nums1[size1--];
		}
		while(j>=0)
		{
			nums[k--]=nums2[size2--];
		}
	}
	
}

快排

基本思想是采用分治法(Divide and Conquer)策略来把一个序列分为较小和较大的两个子序列,然后递归地对这两个子序列进行排序。快速排序通常比其他基于比较的排序算法更快,在实际应用中非常广泛。

快速排序的基本步骤:
选择基准(Pivot): 从数组中选择一个元素作为基准。
分区操作(Partitioning): 重新排列数组,所有小于基准的元素都排在基准前面,所有大于基准的元素都排在基准后面。这个操作完成后,基准元素就位于其最终位置。
递归排序子数组:
对基准左侧的子数组递归执行上述步骤。
对基准右侧的子数组递归执行上述步骤。
快速排序算法有两个核心点,分别为 哨兵划分 和 递归 。
哨兵划分:
以数组某个元素(一般选取首元素)为 基准数 ,将所有小于基准数的元素移动至其左边,大于基准数的元素移动至其右边。
递归:
对 左子数组 和 右子数组 分别递归执行 哨兵划分,直至子数组长度为 1 时终止递归,即可完成对整个数组的排序。

class Solution{
publicvoid partition(vector<int>& nums,int l.int r)
	{
		//此处以nums[l]为基准
		int i=l,j=r;
		while(i<j)
		{
			while(i<j && nums[i]<=nums[l])i++;
			while(i<j && nums[j]>=nums[l])j--;
			swap(nums[i],nums[j]);
		}
		swap(nums[i],nums[j]);
		return i;
	}
	void quickSort(vector<int>& nums,int l.int r)
	{
		if(l>=r) return;
		int pi=partition(nums,l,r);
		quickSort(nums,l,pi-1);
		quickSort(nums,pi+1,r);
	}
	
}

两数之和

链接: leetcode

题目描述:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

解题思路:unordered_map存储


class Solution{
public:
	vector<int> twoSum(vector<int>& nums,int target)
	{
		unordered_map<int,int> has;
		for(int i=0;i<nums.size();i++)
		{
			auto it=has.find(target-nums[i]);
			if(it !=has.end())
			{
				return {it->second,i};
			}
			has[nums[i]]=i;
		}
		return {};
	}
	
}

最长回文子串

链接: leetcode

题目描述:给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的回文串的长度。

解题思路:回文串倒序后与自身完全相同,当回文串长度为偶数所有字符出现偶数次,当回文串长度为奇数除了中间字符出现奇数次,其余都出现偶数次,因此可以用哈希表计数,遍历统计构造回文串的最大长度


class Solution {
public:
    int longestPalindrome(string s) {
        unordered_map<char,int> counter;
        for(char c:s)
        {
            counter[c]++;
        }
        int res=0,odd=0;
        for(auto n:counter)
        {
            int count =n.second;
            int re=count%2;
            res+=count-re;
            if(re==1) odd=1;
        }
        return res+odd;
    

    }
};

求二叉搜索树的最近公共祖先

链接: leetcode

题目描述:给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

解题思路:迭代,分析pq是否在root的同一子树,进一步深度遍历


/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root,TreeNode*p,TreeNode*q)
    {
        if(root==NULL) return root;
        if(root->val > p->val && root->val > q->val)
        {
            TreeNode* left=lowestCommonAncestor(root->left,p,q);
            if(left!=NULL) return left;
        }
        if(root->val < p->val && root->val < q->val)
        {
            TreeNode* right=lowestCommonAncestor(root->right,p,q);
            if(right!=NULL) return right;
        }
        return root;

    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值