总结
首先华为牛客的面试题库是非常leetcode的,它的题目非常的常规,但是真正招实习生的时候,往往不是这么简单,笔试的题目设计的是真正的应用题,在这个时候,如何更好更完整的把题目的含义从中抽象出来才是问题的关键,所以到时候真的需要额外的去准备类似的题目,只是刷leetcode是不够的。
链表
1、反转链表
输入一个链表,反转链表后,输出新链表的表头
解题分析:这个时候我们就考虑这样的情况,有两个节点,一个是已经经过反转的头节点,一个是目前还没有反转的头节点,如何进行这两个节点的连接,已经移动到下一个类似的情况,注意这里是不需要额外的设置哨兵节点。
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(pHead==NULL) return pHead;
ListNode* pre = NULL, *val = pHead,*tmp;
while(val)
{
tmp = val->next;
val->next = pre;
pre = val;
val = tmp;
}
return pre;
}
};
2、合并有序链表
将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的,且合并后新链表依然有序
题目分析:简单题目,这里只需要额外的设置一个哨兵节点就可以很方便的移动的,而且也要主要退出循环的问题(链表的长度是不同的)
/**
* 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*l3 = new ListNode(0),*head = l3;
while(l1&&l2)
{
if(l1->val>l2->val)
{
l3->next = l2;
l2 = l2->next;
}
else
{
l3->next = l1;
l1 = l1->next;
}
l3 = l3->next;
}
l3->next = (l1?l1:l2);
l3 = head->next;
delete head;
return l3;
}
};
3、两个链表的第一个公共节点
题目分析:这里就是使用双指针来处理,分别设置两个指针分别指向两个链表的头部,之后分别进行移动之后,如果到达各自链表的最后一个点之后,下一次移动到另一条链表上去,如果两个链表有公共节点,在第二次在另一个链表遍历的时候一定是能够找到对应的链表节点相同的位置。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
//这里就要注意,有可能是没有所谓的公共节点的,这个时候就要直接输出NULL
ListNode *tmp1 = pHead1,*tmp2 = pHead2;
while(tmp1!=tmp2)
{
tmp1 = tmp1?tmp1->next:pHead2;
tmp2 = tmp2?tmp2->next:pHead1;
}
return tmp1;
}
};
4、链表相加
解题分析:这里主要是可以首先将两个链表转为字符串,之后再根据字符串的相加原理的得到十进制方式的字符串,之后再根据这个字符串来建立一个链表,将它返回。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head1 ListNode类
* @param head2 ListNode类
* @return ListNode类
*/
//这里是出现了溢出的问题
string num(ListNode*head)
{
string ans;
while(head)
{
ans += to_string(head->val);
head = head->next;
}
return ans;
}
ListNode* build_list(const string& str)
{
ListNode*h = new ListNode(0), *head = h,*tmp;
for(int i = 0;i<str.length();++i)
{
tmp = new ListNode(str[i]-'0');
h->next = tmp;
h = tmp;
}
tmp = head->next;
delete head;
return tmp;
}
ListNode* build(const string& s1,const string& s2)
{
string ans;
int i = s1.length()-1, j = s2.length()-1, add = 0;
while(i>=0||j>=0||add!=0)
{
int x = i>=0?s1[i]-'0':0;
int y = j>=0?s2[j]-'0':0;
int result = x+y+add;
ans.push_back('0'+result%10);
add = result/10;
--i;
--j;
}
reverse(ans.begin(), ans.end());
return build_list(ans);
}
ListNode* addInList(ListNode* head1, ListNode* head2) {
// write code here
//一个是翻转 一个是转换成数字的形式来解决
string m = num(head1), n = num(head2);
return build(m,n);
}
};
5、判断一个链表是否是回文链表
给定一个链表,请判断该链表是否为回文结构
解题分析:对于回文的判断,一般就是要判断从中部出发向两边延展,不断的判断两侧是否相等,当然这个方向可以是相反的,也就是从两侧向中间汇聚。当然也可以使用栈等方式来处理,也可以将原本复杂的结构放到线性结构上处理,比如数组等。当然这里的话主要是通过快慢指针找到链表的中点,而后将这个点之后的链表进行反转,反转之后分别进行比较。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类 the head
* @return bool布尔型
*/
ListNode* reverse(ListNode*root)
{
if(!root) return nullptr;
ListNode* head = nullptr, *h = head,*tmp;
while(root->next)
{
tmp = root->next;
root->next = head;
head = root;
root = tmp;
}
root->next = head;
return root;
}
bool isPail(ListNode* head) {
// write code here
//使用快慢指针找到中点,然后对后面的进行链表的翻转,然后使用双指针的方式进行比较和遍历
if(head==nullptr||head->next==nullptr) return true;
ListNode* low = head, *fast = head,*h1 = head,*h2;
while(fast->next&&fast->next->next)
{
low = low->next;
fast = fast->next->next;
}
h2 = reverse(low);
while(h1&&h2)
{
if(h1->val!=h2->val) return false;
h1 = h1->next;
h2 = h2->next;
}
return true;
}
};
6、链表的奇偶重排
解题分析:这里主要是考虑两个指针,一个针对于奇数节点,一个针对于偶数节点,主要是要小心循环的判断条件就可以了。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @return ListNode类
*/
ListNode* oddEvenList(ListNode* head) {
// write code here
//这里直接使用双指针,可以吗
if(head==nullptr||head->next==nullptr) return head;
ListNode* p1 = head, *p2 = head->next, *ph1 = p1, *ph2 = p2;//p1表示的是奇数节点的头部,p2表示的是偶数节点的头部
while(p2&&p2->next)
{
p1->next = p2->next;
p2->next = p2->next->next;
p1 = p1->next;
p2 = p2->next;
}
p1->next = ph2;
return ph1;
}
};