反转链表
定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。
数据范围
链表长度 [0,30]。
样例
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
我们利用双指针,一个指针指向第一个,另一个指向后一个,然后让后面的指向前面的(本来是前面的指向后面的),之后让两个指针都向后移一位,然后重复上述行为即可
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head||!head->next){
return head;
}
auto p=head,q=head->next;
while(q){
auto o=q->next;
q->next=p;
p=q,q=o;
}
head->next=NULL;
return p;
}
};
两个链表的第一个公共结点
输入两个链表,找出它们的第一个公共结点。
当不存在公共节点时,返回空节点。
数据范围
链表长度 [1,2000]。
保证两个链表不完全相同,即两链表的头结点不相同。
样例
给出两个链表如下所示:
输出第一个公共节点c1
如果有公共结点肯定是在后面重叠,且后面部分都是共同的。
方法1:先计算出两个链表的长度,可以让比较长的先走两个链表长度之差的步数,两个再一起走。
方法2:不同部分为a, 和b,公共部分为c;a + c + b = b + c + a;让两个一起走,a走到头就转向b, b走到头转向a,则在公共部分相遇。
设A链表的非公共部分长度为LA,B链表的非公共部分长度为LB,公共部分长度为C。
A链表总长度为LA + C,B链表总长度为LB + C。
当指针按照题解方式走下去,p1第二次走到公共节点的时候,走过的长度为LA + C + LB,p2第二次走到公共节点的时候,走过的长度为LB + C + LA。p1 p2走过的长度相等,p1 p2 相遇。
所以,当p1 p2 相遇(相等)的时候,指向的节点就是公共节点。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p1 = headA;
ListNode *p2 = headB;
while (p1 != p2) {
if(p1 != NULL)//p1没有走到结尾
p1 = p1->next;//p1指向下一个节点
else//p1走到结尾
p1 = headB;//p1指向另一个链表头
if(p2 != NULL)//p2没有走到结尾
p2 = p2->next;//p2指向下一个节点
else //p2走到结尾
p2 = headA;//p2指向另一个链表头
}
return p1;
}
};
用两个栈实现队列
请用栈实现一个队列,支持如下四种操作:
push(x) – 将元素x插到队尾;
pop() – 将队首的元素弹出,并返回该元素;
peek() – 返回队首元素;
empty() – 返回队列是否为空;
注意:
你只能使用栈的标准操作:push to top,peek/pop from top, size 和 is empty;
如果你选择的编程语言没有栈的标准库,你可以使用list或者deque等模拟栈的操作;
输入数据保证合法,例如,在队列为空时,不会进行pop或者peek等操作;
数据范围
每组数据操作命令数量 [0,100]。
样例
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // returns 1
queue.pop(); // returns 1
queue.empty(); // returns false
我们可以用两个栈来实现,一个栈来缓冲,当我们插入时插入至第一个栈,弹出时先将剩余元素放置缓冲栈中,就可以将第一个元素弹出来了
我们用两个栈来做,一个主栈,用来存储数据;一个辅助栈,用来当缓存。
push(x)
,我们直接将x插入主栈中即可。
pop()
,此时我们需要弹出最先进入栈的元素,也就是栈底元素。我们可以先将所有元素从主栈中弹出,压入辅助栈中。则辅助栈的栈顶元素就是我们要弹出的元素,将其弹出即可。然后再将辅助栈中的元素全部弹出,压入主栈中。
peek()
,可以用和pop()操作类似的方式,得到最先压入栈的元素。
empty()
,直接判断主栈是否为空即可。
时间复杂度分析
push()
:O(1);
pop()
: 每次需要将主栈元素全部弹出,再压入,所以需要 O(n) 的时间;
peek()
:类似于pop(),需要 O(n) 的时间;
empty()
:O(1);
class MyQueue {
public:
/** Initialize your data structure here. */
stack<int>s1,s2;
MyQueue() {
}
/** Push element x to the back of queue. */
void push(int x) {
s1.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
while(s1.size()>1)s2.push(s1.top()),s1.pop();
int t=s1.top();
s1.pop();
while(s2.size())s1.push(s2.top()),s2.pop();
return t;
}
/** Get the front element. */
int peek() {
while(s1.size()>1)s2.push(s1.top()),s1.pop();
int t=s1.top();
while(s2.size())s1.push(s2.top()),s2.pop();
return t;
}
/** Returns whether the queue is empty. */
bool empty() {
return s1.empty();
}
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* bool param_4 = obj.empty();
*/
和为S的两个数字
输入一个数组和一个数字 s,在数组中查找两个数,使得它们的和正好是 s。
如果有多对数字的和等于 s,输出任意一对即可。
你可以认为每组输入中都至少含有一组满足条件的输出。
数据范围
数组长度 [1,1002]。
样例
输入: [1,2,3,4] , sum=7
输出: [3,4]
我们可以用哈希表来做,扫描到每个数时我们看一下这个数前面有没有可以和它一起和为s的数,看下一个的时候将先看的那个放入哈希表里面便于查找
class Solution {
public:
vector<int> findNumbersWithSum(vector<int>& nums, int target) {
unordered_set<int>s;
for(auto x:nums){
if(s.count(target-x))return {x,target-x};//判断存不存在用count函数
s.insert(x);
}
}
};