执行用时 :8 ms, 在所有 C++ 提交中击败了76.49%的用户
内存消耗 :13.3 MB, 在所有 C++ 提交中击败了86.78%的用户
class Solution {
public:
vector> zigzagLevelOrder(TreeNode* root) {
vector >result;
if(root==nullptr)
return result;
stack S1,S2;
S1.push(root);
int flag=1;//左孩子先入栈,右孩子先出栈
TreeNode* tmp;
vector vec;
while(!S1.empty() or !S2.empty()){
if(!vec.empty()){
result.push_back(vec);
vec.clear();
}
if(!S1.empty()){
while(!S1.empty()){
tmp=S1.top();
S1.pop();
vec.push_back(tmp->val);
if(flag==1){
if(tmp->left)
S2.push(tmp->left);
if(tmp->right)
S2.push(tmp->right);
}else{
if(tmp->right)
S2.push(tmp->right);
if(tmp->left)
S2.push(tmp->left);
}
}
flag=0-flag;
}
else{
while(!S2.empty()){
tmp=S2.top();
S2.pop();
vec.push_back(tmp->val);
if(flag==1){
if(tmp->left)
S1.push(tmp->left);
if(tmp->right)
S1.push(tmp->right);
}else{
if(tmp->right)
S1.push(tmp->right);
if(tmp->left)
S1.push(tmp->left);
}
}
flag=0-flag;
}
}
result.push_back(vec);
return result;
}
};
链表反序
leetcode206
leetcode92
206题代码如下:
执行用时 :12 ms, 在所有 C++ 提交中击败了84.92%的用户
内存消耗 :9.3 MB, 在所有 C++ 提交中击败了9.63%的用户
#include
#include
using namespace std;
struct ListNode{
int val;
ListNode *next;
ListNode(int x):val(x),next(nullptr){}
};
ListNode* reverseList(ListNode* head) {
if(head== nullptr or head->next==nullptr)
return head;
ListNode* tail=nullptr;
ListNode* newhead=nullptr;
while(head){
newhead=head;
head=head->next;
newhead->next=tail;
tail=newhead;
}
head=newhead;
tail=nullptr;
newhead= nullptr;
return head;
}
ListNode* buildList(vector vec){
ListNode* head=nullptr;
if(vec.empty())
return head;
for(int i=vec.size()-1;i>=0;--i){
ListNode* tmp=new ListNode(vec[i]);
tmp->next=head;
head=tmp;
}
return head;
}
void destorylist(ListNode* head){
if(head==nullptr)
return;
ListNode* tmp=nullptr;
while(head){
tmp=head;
head=head->next;
delete tmp;
}
}
int main(){
vector vec{1,2,3,4,5,6,7};
ListNode* head=buildList(vec);
head=reverseList(head);
ListNode* tmp=head;
while(tmp){
cout<val<<" ";
tmp=tmp->next;
}
destorylist(head);
return 0;
}
输出结果:7 6 5 4 3 2 1
92题是一个中等难度的题,反转从位置m到位置n进行反转。
执行用时 :8 ms, 在所有 C++ 提交中击败了55.01%的用户
内存消耗 :8.6 MB, 在所有 C++ 提交中击败了79.29%的用户
ListNode* reverseBetween(ListNode* head, int m, int n) {
if(head==nullptr or head->next==nullptr){
return head;
}
ListNode* q=nullptr;//记录反转的前一个结点
ListNode* q1=head;//记录反转链表头节点
ListNode* p=nullptr;//反转后反转链表的头结点
for(int i=1;inext;//找到反转链表头节点
}
ListNode* tail=q1;//记录反转链表尾结点后的一个结点
for(int i=m;i<=n;++i){
tail=tail->next;
}
while(m<=n){
p=q1;
q1=q1->next;
p->next=tail;
tail=p;
++m;
}
if(q){
q->next=p;
return head;
}
return p;
}
写一下二叉树深度遍历非递归。
DFS是指,对每个分支的可能分支深入到不能深入为止。就是说把一个分支访问完才能访问其他分支。树的深度优先遍历就是先序遍历。
非递归,借助栈完成DFS(depthFirstSearch)。
void BFS(Tree *root){
if(root==nullptr){
return;
}
stack S1;
S1.push(root);
Tree *tmp=nullptr;
while(!S1.empty()){
tmp=S1.top();
cout<data<<" ";
S1.pop();
if(tmp->right)
S1.push(tmp->right);
if(tmp->left)
S1.push(tmp->left);
}
cout<
深度优先遍历的递归写法:
void BFS(Tree *root){
if(root==nullptr){
return;
}
cout<data<<" ";
BFS(root->left);
BFS(root->right);
}
同时再写一下广度优先遍历:
void DFS(Tree *root){
if(root==nullptr){
return;
}
stack S1,S2;//S1用来存储结点,S2作为临时交换用的空间
S1.push(root);
Tree* tmp;
while(!S1.empty()){
if(!S1.empty()){
while(!S1.empty()){//每次从S1读取数据
tmp=S1.top();
cout<data<<" ";
S1.pop();
if(tmp->left)//左孩子先入S2栈,后面利用S2出栈后,就成了左孩子后入S1
S2.push(tmp->left);
if(tmp->right)
S2.push(tmp->right);
}
while(!S2.empty()){//S2作为临时交换用
tmp=S2.top();
S2.pop();
S1.push(tmp);
}
}
}
}
利用队列实现广度优先遍历的话,只需要一个队列就行,可以节省开销,具体如下:
void DFS(Tree *root) {
if (root == nullptr) {
return;
}
queue Q;
Q.push(root);
Tree* tmp;
while(!Q.empty()){
tmp=Q.front();
Q.pop();
cout<data<<" ";
if(tmp->left)
Q.push(tmp->left);
if(tmp->right)
Q.push(tmp->right);
}
}
int removeDuplicates(vector& nums) {
if(nums.size()<=1)
return nums.size();
int i=0,j=1;
while(j
执行用时 :144 ms, 在所有 C++ 提交中击败了27.81%的用户
内存消耗 :12.6 MB, 在所有 C++ 提交中击败了100.00%的用户
void swap(int &a,int &b){
int tmp=a;
a=b;
b=tmp;
}
int partition(vector &nums,int lo,int hi){
swap(nums[lo],nums[lo+rand()%(hi-lo+1)]);
int pivot=nums[lo];
int mi=lo;
for(int k=lo+1;k<=hi;k++)
if(nums[k]& nums,int lo,int hi){
if(lo sortArray(vector& nums) {
int lo=0,hi=nums.size()-1;
quicksort(nums,lo,hi);
return nums;
}
topk快排算法
topk问题有两种类型:1.海量数据里面选出最大的前k个数,问法有一亿个数据找到前k大的数据,或者找到第k大的数据;2.从很大一个数组里面选出最大的前k个数。
问题1的情况,数据无法存储,因此也无法通过排序来选出前k个数;问题2是可以把数据存储起来,可以对数组进行排序之后,取前k个数。
对于问题2,可以借助快排来找到前k个数。快速排序需要找到一个轴点,轴点右边的数均大于轴点,左边的数均小于轴点,因此如果找到一个轴点,加上轴点及其右边的数的个数为K,那么我们就找到了这最大的前K个数。在进行partition的过程中,设轴点右边的数的个数为x,有如下几种情况:
1.x
3.x>K-1时,我们要找的轴点一定在此轴点的右边,对右边的数进行partition。
输出的结果不一定有序。
时间复杂度分析:最坏情况下,轴点从数组第一个位置移动到倒数第K个位置,partition次数为N-K,一次partition的时间复杂度为:O(hi-lo),时间复杂度T(n)=(N+N-1+N-2+...+(K+1))≈O(N^2)。
int partition(vector &nums,int lo,int hi){
swap(nums[lo],nums[lo+rand()%(hi-lo+1)]);
int pivot=nums[lo];
int mi=lo;
for(int k=lo+1;k<=hi;k++)
if(nums[k] &nums,int lo,int hi,int K){
int pivot=partition(nums,lo,hi);
if(hi-pivot+1==K){//找到了这个轴点
for(int i=0;i<(nums.size()-pivot);++i){
cout< vec{1,2,9,3,11,4,21,5,55,6,10,7};
int lo=0,hi=vec.size()-1;
int K=3;
topK(vec,lo,hi,K);
return 0;
}
输出结果:
11 21 55
下面介绍一下第一种情况的算法:
无法通过数组进行简单排序时,我们应该想到应用堆排序,构建大小为K的小顶堆,对于输入的数据,如果小于堆顶,则丢弃这个数据,如果大于堆顶,则用此数据替换堆顶,再进行下溢,直到所有数据输入完毕。
时间复杂度分析:对数据进行下溢最坏的情况为堆的高度,就是logK,假设海量数据为N,那么时间复杂度T(n)=O(NlogK)。
使用STL算法里优先队列解决这个问题,STL优先队列本身就是通过二叉堆实现的,最小优先队列的第一个元素就是最小堆堆顶元素。(这里需要去了解stl里queue的性质和用法)
#include
#include
#include
using namesapce std;
int main(){
priority_queue,greater > minHeap;
int K;
cin>>K;
int tmp,i=0;
while(cin>>tmp){
if(iminHeap.top()){
minHeap.pop();
minHeap.push(tmp);
}
}
}
for(int i=0;i
输出结果:
6 3 8 11 13 15 54 32 7 87 65 42 14 23 35 57 79 12
^D
42 54 57 65 79 87
执行用时 :304 ms, 在所有 C++ 提交中击败了46.42%的用户
内存消耗 :16.1 MB, 在所有 C++ 提交中击败了69.26%的用户
vector dailyTemperatures(vector& T) {
int n=T.size();
vector result(n,0);
stack S;
for(int i=0;iT[S.top()]){
result[S.top()]=i+1-S.top();
S.pop();
}
}
return result;
}
执行用时 :24 ms, 在所有 C++ 提交中击败了49.68%的用户
内存消耗 :17.4 MB, 在所有 C++ 提交中击败了16.31%的用户
bool isBalanced(TreeNode* root) {
if(root==nullptr)
return true;
if(abs(depth(root->left)-depth(root->right))>1)
return false;
return isBalanced(root->left)&&isBalanced(root->right);
}
int depth(TreeNode* root){
if(root==nullptr)
return 0;
return max(depth(root->left),depth(root->right))+1;
}
这里需要弄清一个最熟悉的算法,并能很清楚的讲解,最好还能有改进版,或者不同版本。