Something learned from leetcode (1)
来源:互联网 发布:儿童编程培训班 编辑:程序博客网 时间:2024/05/22 11:46
1、 STL位操作取1的个数
bitset<32> bv(number);bv.count();
from 338. Counting Bits
2、 Nim Game
取石子游戏,获胜条件 n%4==0必输,其他必胜
bool canWinNim(int n) { if(n%4==0) return false; else return true; }
from 292. Nim game
3、求和(不使用+and-)
设a,b为两个二进制数,a^b为结果,a&b为进位。则a+b = a^b + (a&b)<<1 ,不停迭代直到进位为0 (^为xor, &与)
int getSum(int a, int b) { int tempRs,carry; tempRs=(a^b); carry=a&b; while(carry){ int t_a=tempRs; int t_b=carry<<1; tempRs=t_a^t_b; carry=t_a&t_b; } return tempRs; }
from 371. Sum of Two Integers
4、找出落单的数
数组中两两相同,有一数落单,找出该数。
O(n) 方法原理:
A XOR A = 0
A XOR 0 = A
XOR 运算是可交换的==>
(2^1^4^5^2^4^1) => ((2^2)^(1^1)^(4^4)^(5)) => (0^0^0^5) => 5
int singleNumber(vector<int>& nums) { int res; int temp; for(int i=0;i<nums.size();i++){ temp=res^nums[i]; //所有数字异或,结果即为落单的数 res=temp; } return res; }
from 136. Single Number | 389.Find the difference中有相同应用
5、Add Digits无营养的规律
打印0-20结果后发现规律
1-9循环出现
if(num==0) return 0; if(num%9==0) return 9; return num%9;
from 258. Add Digits
6、struct结构体和二叉树构造
struct TreeNode{ int val; TreeNode *left; TreeNode *right;};TreeNode* CreateBinaryTreeNode(int value){ TreeNode* pNode=new TreeNode(); pNode->val=value; pNode->left=NULL; pNode->right=NULL; return pNode;}//Conect parent and childvoid ConnectNode(TreeNode* Parent,TreeNode* Lchild, TreeNode* Rchild){if(Parent!=NULL){ Parent->left=Lchild; Parent->right=Rchild;}}
构造一棵二叉树,并求高度
int main(){ TreeNode * Node1=CreateBinaryTreeNode(1); TreeNode * Node2=CreateBinaryTreeNode(2); TreeNode * Node3=CreateBinaryTreeNode(3); TreeNode * Node4=CreateBinaryTreeNode(4); TreeNode * Node5=CreateBinaryTreeNode(5); TreeNode * Node6=CreateBinaryTreeNode(6); TreeNode * Node7=CreateBinaryTreeNode(7); /* 1 /\2 3/\ \4 5 6 / 7 */ ConnectNode(Node1,Node2,Node3); ConnectNode(Node2,Node4,Node5); ConnectNode(Node3,NULL,Node6); ConnectNode(Node6,Node7,NULL); int TreeDeep(TreeNode *); cout<<TreeDeep(Node1); return 0;}int TreeDeep(TreeNode* root){ if(root==NULL) return 0; else return 1+ max(TreeDeep(root->left),TreeDeep(root->right));}
同一棵树进行深度优先遍历(DFS)
stack<TreeNode*> s; s.push(Node1); TreeNode* p=s.top(); //遍历指针 while(!s.empty()){ p=s.top(); cout<<p->val<<endl; s.pop(); if(p->right) //栈后进先出,故右子树先入栈,再左子树 s.push(p->right); if(p->left) s.push(p->left); }
from 104. Maximum Depth of Binary Tree
7、没营养之二Rotate Function,硬找规律防TLE
F(0) = 0A + 1B + 2C +3D
F(1) = 0D + 1A + 2B +3C
F(2) = 0C + 1D + 2A +3B
F(3) = 0B + 1C + 2D +3A
sum=A+B+..+N
=》
F(1) = F(0) + sum - 4D
F(2) = F(1) + sum - 4C
F(3) = F(2) + sum - 4B
=>
F(i) = F(i-1) + sum - n*A[n-i]
int maxRotateFunction(vector<int>& A) {int bigNum=0,sum=0,F0,Fprior,n=A.size(); for(int i=0;i<A.size();i++) sum+=A[i]; for(int j=0;j<A.size();j++) F0+=(j*A[j]); bigNum=F0; Fprior=F0; for(int k=1;k<A.size();k++) { Fprior=Fprior+sum-n*A[n-k]; bigNum=max(bigNum,Fprior); } return bigNum; }
from 396 Rotae Function
8、翻转整数Reverse Integer溢出的坑
该题leetcode判定条件为:翻转后超出int表示范围2147483648到-2147483647时直接return 0
from 7.Reverse Integer
9、Two Sum II - Input array is sorted
vector<int> twoSum(vector<int>& numbers, int target) { int low=0,high=numbers.size()-1,temp; while(low<high){ temp=numbers[low]+numbers[high]; if(temp==target){ return vector<int> {low+1,high+1}; } else if(temp>target) high--; else low++; } return vector<int> {0,0};//此句多余,但对应无解状况。 }
from 167.Two Sum II - Input array is sorted
10、落单的数(2数落单),位运算的trick
数组中两两相同,有两数落单,找出该数。
思路:
一、计算数组中所有数字的异或(记为diff),由上面4中所述该值为两个最终结果的异或,即result1 xor result2。
二、result1一定不等于result2,故其二进制表示中一定有至少一位result1不等于result2(设result1该位为0,则在同一位置上,result2一定为1)。
三、根据某一特定二进制位取值的不同,将数组中所有数字分成两组,一组该位为0,一组该位为1。由第二条知,此时result1和result2分别处于两组中。且各个组其他元素必成对出现(因为相同的数所有二进制位均相同),此时调用落单的数1.0版(1数落单)中的方法把它找出来。
寻找这一特定二进制位, that’s a trick
求法: diff&=(-diff)
得到的结果diff为从右数第一个不为零的位=1,其他位=0。
例如所有数异或结果diff=0110(十进制6), -diff=1010(十进制-6的补码)
diff&=(-diff)之后diff=0010
此时用数组中的num&diff 就能按倒数第二位是0,或1 分成两组。
另:寻找该二进制位有其他解法,即找出两结果中其他差异二进制位(不一定是右边第一个不为零的位),此时可按这个位划分原数组。
vector<int> singleNumber(vector<int>& nums) { int diff=0; for(int i=0;i<nums.size();i++) diff^=nums[i]; diff&=(-diff); vector<int> res={0,0}; for(int j=0;j<nums.size();j++) { /* 此处开始没加括号即if(diff&nums[j]==0)结果出错(gcc),考虑是否为符号优先级问题,待证实。 */ if((diff&nums[j])==0) res[0]^=nums[j]; else res[1]^=nums[j]; } return res; }
from 260. Single Number III
11、二叉树DFS的应用,Sum of Left Leaves
该篇第6点中有二叉树及DFS基础知识。
Testcase用数组形式表示二叉树,[3,9,20,null,null,15,7]的形状为
3 / \ 9 20 / \ 15 7
判断左叶子的方法:
p->left!=NULL&&p->left->left==NULL&&p->left->right==NULL//'3'有左子树,'3'的左子树'9'是叶节点,则'3'的左子树满足要求
主要代码源于4中的DFS。
int sumOfLeftLeaves(TreeNode* root) { int res=0; stack<TreeNode*> s; if(root==NULL) //判断空树的方法,对应testcase:[] return 0; s.push(root); TreeNode* p=s.top(); while(!s.empty()){ p=s.top(); if(p->left!=NULL&&p->left->left==NULL&&p->left->right==NULL) res+=p->left->val; s.pop(); if(p->right) s.push(p->right); if(p->left) s.push(p->left); } return res; }
from 404. Sum of Left Leaves
12、数组自乘,0的处理
题目简单,求所有数乘积,除以nums[i]即为该位置的最终结果。提交后报Compiler Error,明显除零错误。
剪枝方法:
此题可添加一个zeroCount变量,减少不必要的运算。若该变量>=2,即有两个或以上的0,则结果全零直接返回。
若zeroCount=1,单独处理。zeroCount=0则按上述报CE的方法处理。
于是在Submission Details中罕见的看到了一次超过50%的评价,“Your runtime beats 91.91% of cpp submissions.”
vector<int> productExceptSelf(vector<int>& nums) { long long int multi=1; int zeroCount=0,zeroPos; //zeroPos只在处理一个0时用到 //目的是减少一次大循环 vector<int> res; for(int i=0;i<nums.size();i++){ multi*=nums[i]; if(nums[i]==0){ zeroCount++; zeroPos=i; } if(zeroCount>1){ for(int k=0;k<nums.size();k++) res.push_back(0); return res; } } //for if(zeroCount==1){ multi=1; for(int m=0;m<nums.size();m++){ if(m!=zeroPos){ res.push_back(0); } else { for(int n=0;n<nums.size();n++){ if(n!=zeroPos) multi*=nums[n]; } res.push_back(multi); } } //outer for return res; } //outer if for(int j=0;j<nums.size();j++) res.push_back((int)multi/nums[j]); return res; }
from 238. Product of Array Except Self
13、单链表结构及删除给定节点
单链表1->2->3->4, 给定3的地址,将其从链表中删除,结果为1->2->4。
注: 表头地址未知,删除位置不为最后节点。
思路:
由于表头未知无法顺序遍历,无法找到节点2的位置。此时可将待删除节点3的空间用作储存4,将4删除。偷天换日。
如1->2->4->4,将最后一个4删除即为所得结果。
void deleteNode(ListNode* node) { ListNode* temp; node->val=node->next->val; if(node->next->next!=NULL){ temp=node->next; node->next=node->next->next; delete temp; } else{ temp=node->next; node->next=NULL; delete temp; } }
链表结构练习,与二叉树节点类似,分为建立节点和建立连接两个步骤:
struct ListNode{ int val; ListNode* next; };ListNode* CreatListNode(int value){ ListNode* LNode=new ListNode(); LNode->val=value; LNode->next=NULL; return LNode;}void ConnectListNode(ListNode* priorNode, ListNode* afterNode){ if(priorNode!=NULL){ priorNode->next=afterNode; }}
实现该题(自行处理IO)并打印内存泄露处理过程:
int main(){ ListNode* Node1=CreatListNode(1); ListNode* Node2=CreatListNode(2); ListNode* Node3=CreatListNode(3); ListNode* Node4=CreatListNode(4); /* 1->2->3->4 */ ConnectListNode(Node1,Node2); ConnectListNode(Node2,Node3); ConnectListNode(Node3,Node4); ListNode* p=Node1; //用于删除后打印链表最终形态的遍历指针 ListNode* deleteNode=Node2; //删除节点2 ListNode* temp=deleteNode; cout<<"Node1 address="<<Node1<<endl; cout<<"Node2 address="<<Node2<<endl; cout<<"Node3 address="<<Node3<<endl; cout<<"Node4 address="<<Node4<<endl; deleteNode->val=deleteNode->next->val; if(deleteNode->next->next!=NULL){ temp=deleteNode->next; deleteNode->next=deleteNode->next->next; //此处并不会改变temp的值,temp依旧指向上一步地址 cout<<"实际释放的address="<<temp<<endl; delete temp; //防止内存泄露 } else{ temp=deleteNode->next; deleteNode->next=NULL; cout<<"实际释放的addres"<<temp<<endl;; delete temp; } cout<<"此时链表形态为"<<endl; while(p->next!=NULL){ cout<<p->val<<"->"; p=p->next; } cout<<p->val<<endl; return 0;}
该程序的std out结果如下:
Node1 address=0x340f48Node2 address=0x340fc8Node3 address=0x340fd8Node4 address=0x340fe8实际释放的address=0x340fd8此时链表形态为1->3->4
删除节点2时,可以看到实际释放的空间是原Node3的地址。
from 237. Delete Node in a Linked List
14、蓄水池抽样(reservoir sampling)
典型应用场景为数据流,数据个数未知且每次只能读取一个数据。如何随机取到一个数据并且保证取到每个数据的概率相等。
随机取一个数据的情形:
[1,2,3]
蓄水池reservoir大小为1
1.取第一个数放入蓄水池,reservoir=1。
2.之后读到第i个数时,以1/i的概率决定是否替换掉蓄水池中的数 。if(rand()%i==0) reservoir=Val(i);
3.重复第二步直到结束,此时reservoir中的数即符合要求。
随机取k个数据的情形:
1.取前k个数放入蓄水池
2.之后读到第i个数时,以k/i的概率决定是否替换掉蓄水池中的数,若决定替换,从蓄水池中随机等概率选择一个元素进行。
3.重复第二步直到结束。
证明略。
class Solution {public: /** @param head The linked list's head. Note that the head is guaranteed to be not null, so it contains at least one node. */ ListNode *p; Solution(ListNode* head) { p=head; } /** Returns a random node's value. */ int getRandom() { int res,count=1; ListNode* p1=p; // srand((unsigned)time(NULL)); while(p1){ if(rand()%count==0) res=p1->val; count++; p1=p1->next; } return res; }};
该题leetcode判定貌似有点问题,放弃srand()生成随机seed后以上解法时而AC,时而WA,推测是随机数rand()问题。
15、洗 牌(Shuffle) 算 法,Fisher Yates shuffle algorithm
O(n)时间完成洗牌,各元素位置概率相等。
过程
1. 选中第1个元素,将其与n个元素中任意一个交换(包括第一个元素)
2. 选中第2个元素,将以与n-1个元素中任意一个交换(包括与2自己,但不包括1,因为此时1的位置已经确定)
3. 不断重复,直到最后一个元素
如何生成指定范围随机数
问题:生成[a,b]之间的一个随机数
int range = b-a+1; //总共多少个数int randomNumber = rand()%range +a; //rand()是伪随机数,可以使用time seed,即srand(time(NULL))等随机数生成方法
该题ac代码如下:
class Solution {public: vector<int> resetNums; vector<int> shuffleRes; Solution(vector<int> nums) { for(int i=0;i<nums.size();i++){ resetNums.push_back(nums[i]); shuffleRes.push_back(nums[i]); } } /** Resets the array to its original configuration and return it. */ vector<int> reset() { return resetNums; } /** Returns a random shuffling of the array. */ vector<int> shuffle() { int n=shuffleRes.size(),j; for(int i=0;i<n;i++){ j=(rand()%(n-i))+i; swap(shuffleRes[i],shuffleRes[j]); } return shuffleRes; }};
from 384. Shuffle an Array
16、STL vector排序和去重
STL中Unique函数的作用是去除相邻重复元素
只适合于有序vector,故先排序
sort(res.begin(),res.end()); //排序vector<int>::iterator iter;iter = unique(res.begin(),res.end()); res.erase(iter,res.end());
此时res容器不含相同元素。缺点是打乱了原数组的顺序,但符合本题要求。
以下解法效率低下,不断遍历较短的数组以期减少运算,但本质仍是蛮力算 法。
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { vector<int> shortArray; vector<int> longArray; vector<int> res; vector<int>::iterator iter; int k; if(nums1.size()<=nums2.size()){ shortArray=nums1; longArray=nums2; } else { shortArray=nums2; longArray=nums1; } for(int i=0;i<longArray.size();i++){ k=0; for(;k<shortArray.size();k++){ if(longArray[i]==shortArray[k]){ res.push_back(shortArray[k]); break; } } } sort(res.begin(),res.end()); iter = unique(res.begin(),res.end()); res.erase(iter,res.end()); return res; }
STL std::set解决
set_intersection函数
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { vector<int> res; set<int> set_nums1(nums1.begin(),nums1.end()); set<int> set_nums2(nums2.begin(),nums2.end()); /*set_intersection(InputIterator1 first1, InputIterator1 last1,InputIterator2 first2, InputIterator2 last2,OutputIterator result);back_inserter 是iterator适配器,它使得元素被插入到作为实参的某种容器的尾部*/ set_intersection(set_nums1.begin(),set_nums1.end(),set_nums2.begin(),set_nums2.end(),back_inserter(res)); return res; }
使用set做此题:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { vector<int> res; set<int> set_nums1(nums1.begin(),nums1.end()); set<int> set_nums2(nums2.begin(),nums2.end()); set_intersection(set_nums1.begin(),set_nums1.end(),set_nums2.begin(),set_nums2.end(),back_inserter(res)); return res; }
性能提高到16ms,仍然偏低。
from 349. Intersection of Two Arrays
17、判断两颗二叉树是否相同
分为递归解法和非递归解法
递归解法:
bool isSameTree(TreeNode* p, TreeNode* q) { if(p==NULL && q==NULL) return true; if(p==NULL && q!= NULL || p!=NULL && q==NULL || p->val!=q->val) return false; return isSameTree(p->left,q->left)&& isSameTree(p->right,q->right); }
非递归解法:
bool isSameTree(TreeNode* p, TreeNode* q) { if(p==NULL && q==NULL) return true; if(p==NULL && q!= NULL) return false; if(p!=NULL && q==NULL) return false; stack<TreeNode*> s1,s2; s1.push(p); s2.push(q); TreeNode* pointer1=s1.top(); TreeNode* pointer2=s2.top(); while(!s1.empty()){ pointer1=s1.top(); pointer2=s2.top(); if(pointer1->val!=pointer2->val) return false; s1.pop(); s2.pop(); if(pointer1->right== NULL && pointer2->right!=NULL) return false; if(pointer1->right!= NULL && pointer2->right==NULL) return false; if(pointer1->right) s1.push(pointer1->right); if(pointer2->right) s2.push(pointer2->right); if(pointer1->left== NULL && pointer2->left!=NULL) return false; if(pointer1->left!= NULL && pointer2->left==NULL) return false; if(pointer1->left) s1.push(pointer1->left); if(pointer2->left) s2.push(pointer2->left); } return true; }
from 100. Same Tree
18、STL map、multimap和sort()综合使用
map中一个key值只能对应一个value,即m.count()返回值只能为0和1,表示该value是否存在于map。(使用map时注意:使用下标(即key)访问不存在的元素将导致map中添加一个元素,此元素的key为下标值)
map <string,int> testMap;testMap["abc"]=1;
此例中testMap先查找“abc”,没有找到,此时会添加“abc”到testMap中。map在内存中是按key升序连续存储的。
multimap可以实现一对多的映射,且m.eraser(k)操作会删除所有key值=k的元素,并返回删除元素的个数。
STL sort(iter begin,iter end)默认按升序排序。
sort(iter begin,iter begin, cmp) 通过定义cmp实现按需排序。
bool cmp(pair<int,int>&a, pair<int,int>&b){ return a.second>b.second; //sort()排序条件为按second降序排序。}class Solution {public: vector<int> topKFrequent(vector<int>& nums, int k) { vector<int> res; //使用multimap取各个元素的count multimap<int,int> elemMap; for(int i=0;i<nums.size();i++) elemMap.insert(make_pair(nums[i],i)); //使用map的唯一属性去除重复元素 map<int,int> cnt_value_map; for(int j=0;j<nums.size();j++) cnt_value_map.insert(make_pair(nums[j],elemMap.count(nums[j]))); vector<pair<int,int>> temp(cnt_value_map.begin(),cnt_value_map.end()); sort(temp.begin(),temp.end(),cmp); vector<pair<int,int>>::iterator iter=temp.begin(); //sort只能对线性序列进行排序,map(类似红黑树)不满足要求,故转存到vector中。 for(;k>0;k--){ res.push_back(iter->first); iter++; } return res; }};
该解法效率不高且空间开销高,故当成map练习。翻看discuss,第一次看到刷屏般的c++11,难道要退c99保平安了?
使用heap的解法日后更新。
form 347、Top K Frequent Elements
19、26进制的trick
题目:将int转换成excel列的形式
例如:
1 -> A 2 -> B 3 -> C ... 26 -> Z 27 -> AA 28 -> AB
关键是字母Z的处理,调了一小时才找到(n-1)%26的方法
class Solution {public: string convertToTitle(int n) { string temp;int divN,modN;do{ modN=(n-1)%26; divN=(n-1)/26; n=divN; temp+=(char)(modN+65);}while(divN!=0);char tempVal; //此时string逆序,翻转一次for(int bp=0,ep=temp.size()-1;bp<ep;bp++,ep--){ tempVal=temp[bp]; temp[bp]=temp[ep]; temp[ep]=tempVal;} return temp; }};
姊妹题列号转数字,无营养:
class Solution {public: int titleToNumber(string s) { int res=0,powerFlag=s.size()-1; for(int i=0;i<s.size();i++){ res=res+ (((int)s[i])-64 ) * pow(26,powerFlag); powerFlag--; } return res; }};
from 168. Excel Sheet Column Title & 171. Excel Sheet Column Number
20、Unique Digits
题目:
Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10n.
Example:
Given n = 2, return 91. (The answer should be the total numbers in the range of 0 ≤ x < 100, excluding [11,22,33,44,55,66,77,88,99])
题意是求 不含相同位数字 的个数,如112中含有相同数字1,故不合要求。
当n=1时,0-9均满足,输出10
当n=2时 第一位数字可以取1-9(9个选择)任意数字(如1),第二位数可以取除第一位以外的剩余数字(如10、12、13…19)9个选择11含有相同数字去掉
当n=3时,第三位数字剩8个选择
即从n=2开始,第i位剩余选择为9-i+2
class Solution {public: int countNumbersWithUniqueDigits(int n) { if(n==0) return 1; if(n==1) return 10; int res=10,temp=9; for(int i=2;i<=n;i++){ temp*=(9-i+2); res+=temp; } return res; }};
from 357. Count Numbers with Unique Digits
- Something learned from leetcode (1)
- Something learned from leetcode (2)
- Something learned from leetcode (3)
- Lesson Learned From Project
- What I learned from english
- all things learned from UVC
- Something from work
- download something from slideshare
- GTK+ -- from knowing nothing to knowing something (1)
- Software Development Lessons Learned from Poker
- 8 Management lessons learned from Apple
- Lessons learned from c/c++ defects
- something come from 工资汇总表
- Presentation: what have I learned from MS Team?
- Learned lessons from the largest player (Flickr, YouTube, Google, etc)
- Improve Domain Name Security, Lessons Learned From Domain Name Hijacking
- What I Have Learned From My First Scientific Research
- 8 Things I learned from "High Performance MySQL"
- Android 技巧(一)--SpannableString
- test
- 28. HTTP、SSL/TLS和HTTPS协议的区别与联系
- Neutron 理解 (9): OpenStack 是如何实现 Neutron 网络 和 Nova虚机 防火墙的 [How Nova Implements Security Group and How
- 理解 OpenStack 高可用(HA)(3):Neutron 分布式虚拟路由(Neutron Distributed Virtual Routing)
- Something learned from leetcode (1)
- uLua实现相机跟随
- string 与char 的转换
- 第六节、AHK变量和运算符
- 理解 OpenStack 高可用(HA)(1):OpenStack 高可用和灾备方案 [OpenStack HA and DR]
- web分页
- Python——fifter函数
- 51nod-1686 第K大区间
- 直接插入排序