P129
调整数组顺序使奇数位于偶数前面
void reOrderArray(vector<int> &array) {
int n = array.size();
int left = 0, right = n-1;
while(left < right){
while(left< right){
if((array[left]&1)==1)
left++;
else
break;
}
while(right > left){
if((array[right]&1) ==0)
right--;
else
break;
}
if(left < right){
int tmp = array[right];
array[right]= array[left];
array[left] = tmp;
left++;
right--;
}
}
}
牛客网的题目有另一个约束:奇数和奇数,偶数和偶数之间的相对位置不变
https://www.nowcoder.com/practice/beb5aa231adc45b2a5dcc5b62c93f593?tpId=13&tqId=11166&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
P134
链表中倒数第k个节点
此题要考虑清楚各种情况,代码的鲁棒性要强
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if( pListHead == NULL || k == 0) return NULL; // k==0 要注意
ListNode * quickPoint = pListHead;
for(int i=0; i< k-1; i++){
quickPoint = quickPoint->next;
if(quickPoint == NULL) return NULL;
}
ListNode * slowPoint = pListHead;
while(quickPoint->next){
slowPoint = slowPoint->next;
quickPoint = quickPoint->next;
}
return slowPoint;
}
P139
链表中环的入口节点
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead == NULL) return NULL;
ListNode * quickPoint = pHead->next, * slowPoint = pHead->next;
if(slowPoint==NULL) return NULL;
quickPoint = quickPoint->next;
if(quickPoint==NULL) return NULL;
while(slowPoint!=quickPoint){
slowPoint = slowPoint->next;
quickPoint = quickPoint->next;
if(quickPoint==NULL) return NULL;
quickPoint = quickPoint->next;
if(quickPoint==NULL) return NULL;
}
ListNode * meet = slowPoint;
slowPoint = slowPoint->next;
int cnt = 1;
while(slowPoint != meet){
cnt++;
slowPoint = slowPoint->next;
}
quickPoint = pHead;
slowPoint = pHead;
while(cnt){
quickPoint = quickPoint->next;
cnt--;
}
while(slowPoint != quickPoint){
slowPoint = slowPoint->next;
quickPoint = quickPoint->next;
}
return slowPoint;
}
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead == NULL) return NULL;
ListNode * quickPoint = pHead->next, * slowPoint = pHead->next;
if(slowPoint==NULL) return NULL;
quickPoint = quickPoint->next;
while(quickPoint){
if(quickPoint == slowPoint) break;
slowPoint = slowPoint->next;
quickPoint = quickPoint->next;
if(quickPoint==NULL) return NULL;
quickPoint = quickPoint->next;
}
ListNode * meet = slowPoint;
slowPoint = slowPoint->next;
int cnt = 1;
while(slowPoint != meet){
cnt++;
slowPoint = slowPoint->next;
}
quickPoint = pHead;
slowPoint = pHead;
while(cnt){
quickPoint = quickPoint->next;
cnt--;
}
while(slowPoint != quickPoint){
slowPoint = slowPoint->next;
quickPoint = quickPoint->next;
}
return slowPoint;
}
P142
反转链表
ListNode* ReverseList(ListNode* pHead) {
if(pHead == NULL) return NULL;
if(pHead->next == NULL) return pHead;
ListNode * pre = NULL, * cur = pHead, * tmp = NULL;
while(cur != NULL){
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
P145
合并两个排序的链表
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if( pHead1 == NULL ) return pHead2;
if(pHead2 == NULL) return pHead1;
ListNode * emptyNode = new ListNode(0);
ListNode * pre = emptyNode;
ListNode * cur = NULL, * cur1 = pHead1, * cur2 = pHead2;
while(cur1 != NULL && cur2 != NULL){
if(cur1->val < cur2->val) {
cur = cur1;
cur1 = cur1->next;
}else {
cur = cur2;
cur2 = cur2->next;
}
pre->next = cur;
pre = cur;
}
if( cur1 ){
pre->next = cur1;
}
if(cur2 ){
pre->next = cur2;
}
return emptyNode->next;
}
递归方法
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL) return pHead2;
if(pHead2 == NULL) return pHead1;
if( pHead1->val < pHead2->val) {
pHead1->next = Merge(pHead1->next, pHead2);
return pHead1;
}else{
pHead2->next = Merge(pHead1, pHead2->next);
return pHead2;
}
}
P148
树的子结构
对自己来说,难度有点大
class Solution {
public:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
{
bool result = false;
if(pRoot1!=NULL && pRoot2!=NULL){
if( abs(pRoot1->val - pRoot2->val)<1e-6){
result = isRight(pRoot1, pRoot2);
}
if(!result){
result = HasSubtree(pRoot1->left, pRoot2);
}
if(!result){
result = HasSubtree(pRoot1->right, pRoot2);
}
}
return result;
}
private:
bool isRight(TreeNode * pRoot1, TreeNode * pRoot2){
if(pRoot2 == NULL) return true;
if(pRoot1 == NULL) return false;
if( abs(pRoot1->val - pRoot2->val)<1e-6 ){
return isRight(pRoot1->left, pRoot2->left) && isRight(pRoot1->right, pRoot2->right);
}else
return false;
}
};
P157
二叉树的镜像
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if(pRoot == NULL) return ;
TreeNode * tmp = pRoot->left;
pRoot->left = pRoot->right;
pRoot->right = tmp;
Mirror(pRoot->left);
Mirror(pRoot->right);
}
};
非递归
void Mirror(TreeNode *pRoot) {
if(pRoot == NULL) return ;
queue<TreeNode *> q;
q.push(pRoot);
TreeNode * tmp = NULL;
while(q.size()){
tmp = q.front();
q.pop();
swap(tmp->left, tmp->right);
if(tmp->left) q.push(tmp->left);
if(tmp->right) q.push(tmp->right);
}
}
P159
对称的二叉树
对自己来说,有点难度
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
return isRight(pRoot, pRoot);
}
private:
bool isRight(TreeNode * r1, TreeNode * r2){
if(r1 == NULL && r2 == NULL ) return true;
if(r1 == NULL || r2==NULL) return false;
if( r1->val!= r2->val ) return false;
return isRight(r1->left, r2->right) && isRight(r1->right, r2->left);
}
};
P161
顺时针打印矩阵
https://www.nowcoder.com/profile/6606749/codeBookDetail?submissionId=15814779
vector<int> printMatrix(vector<vector<int> > matrix) {
vector<int> res;
int row = matrix.size();
if(row == 0) return res;
int col = matrix[0].size();
vector<vector<int>> flag(row, vector<int>(col,0));
int i=0, j=0;
int all = row*col;
int cnt=0;
while(cnt<all){
while(j<col && flag[i][j]==0){
res.push_back(matrix[i][j]);
flag[i][j]=1;
cnt++;
j++;
}
j--;
i++;
while(i<row && flag[i][j]==0){
res.push_back(matrix[i][j]);
flag[i][j]=1;
cnt++;
i++;
}
i--;
j--;
while(j>=0 && flag[i][j]==0){
res.push_back(matrix[i][j]);
flag[i][j]=1;
cnt++;
j--;
}
j++;
i--;
while(i>=0 && flag[i][j]==0){
res.push_back(matrix[i][j]);
flag[i][j]=1;
cnt++;
i--;
}
i++;
j++;
}
return res;
}
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
vector<int> res;
int row = matrix.size();
if(row ==0 )return res;
int col = matrix[0].size();
if(col ==0) return res;
int left=0, right=col-1, top=0, bottom= row-1;
while(left<=right && top<=bottom){
for(int i=left;i<=right;i++){
res.push_back(matrix[top][i]);
}
for(int i=top+1; i<= bottom;i++){
res.push_back(matrix[i][right]);
}
if(top < bottom){
for(int i= right-1; i>=left;i--)
res.push_back(matrix[bottom][i]);
}
if(left < right){
for(int i= bottom-1; i>top;i--)
res.push_back(matrix[i][left]);
}
left++;
top++;
right--;
bottom--;
}
return res;
}
};
P165
包含min函数的栈
class Solution {
public:
void push(int value) {
s.push(value);
if( minStack.empty()) minStack.push(value);
else if( minStack.top() < value)
minStack.push(minStack.top());
else
minStack.push(value);
}
void pop() {
if(!s.empty()){
s.pop();
minStack.pop();
}
}
int top() { // 个人觉得在top时也要判断是否空,但是无法在牛客上ac
return s.top();
}
int min() {
return minStack.top();
}
private:
stack<int> s;
stack<int> minStack;
};
P168
栈的压入、弹出序列
https://www.nowcoder.com/profile/8709341/codeBookDetail?submissionId=17099336
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
int len1 = pushV.size(), len2 = popV.size();
int start = 0;
for(int i=0; i< len2; i++){
if(!s.empty() && s.top()== popV[i])
s.pop();
else{
while(start<len1 && pushV[start]!=popV[i]){
s.push(pushV[start]);
start++;
}
if( start >= len1) return false;
else
start++;
}
}
if(s.empty())
return true;
else return false;
}
private:
stack<int> s;
};
P171
从上到下打印二叉树
以下代码是不分行打印二叉树
vector<int> PrintFromTopToBottom(TreeNode* root) {
vector<int> res;
if(root == NULL) return res;
queue<TreeNode *> q;
q.push(root);
TreeNode * tmp= NULL;
while(!q.empty()){
tmp = q.front();
q.pop();
res.push_back(tmp->val);
if(tmp->left) q.push(tmp->left);
if(tmp->right) q.push(tmp->right);
}
return res;
}
以下代码是分行打印二叉树
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int>> res;
if(!pRoot) return res;
queue<TreeNode *> q;
q.push(pRoot);
TreeNode * tmp = NULL;
int k = 0;
while(!q.empty()){
k = q.size();
vector<int> v;
for(int i=0; i< k; i++){
tmp = q.front();
q.pop();
v.push_back(tmp->val);
if(tmp->left) q.push(tmp->left);
if(tmp->right) q.push(tmp->right);
}
res.push_back(v);
}
return res;
}
之字形打印二叉树
方法一:仍用队列
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int>> res;
if(!pRoot) return res;
queue<TreeNode *> q;
q.push(pRoot);
int k = 0;
TreeNode * tmp = NULL;
int flag=0;
while(!q.empty()){
flag = 1- flag;
k = q.size();
vector<int> v;
for(int i=0;i<k;i++){
tmp = q.front();
q.pop();
v.push_back(tmp->val);
if(tmp->left) q.push(tmp->left);
if(tmp->right) q.push(tmp->right);
}
if(flag) res.push_back(v);
else{
reverse(v.begin(),v.end());
res.push_back(v);
}
}
return res;
}
方法二:使用两个栈
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int>> res;
if(!pRoot) return res;
s1.push(pRoot);
TreeNode * tmp = NULL;
while(!s1.empty() || !s2.empty()){
vector<int> v;
if(!s1.empty()){
while(!s1.empty()){
tmp = s1.top();
s1.pop();
v.push_back(tmp->val);
if(tmp->left) s2.push(tmp->left);
if(tmp->right) s2.push(tmp->right);
}
}else{
while(!s2.empty()){
tmp = s2.top();
s2.pop();
v.push_back(tmp->val);
if(tmp->right) s1.push(tmp->right);
if(tmp->left) s1.push(tmp->left);
}
}
res.push_back(v);
}
return res;
}
private:
stack<TreeNode *> s1;
stack<TreeNode *> s2;
};
P180
二叉搜索树的后序遍历序列
此题,对我还是有点难度
class Solution {
public:
bool VerifySquenceOfBST(vector<int> sequence) {
int n = sequence.size();
if(n==1) return true;
if(n==0) return false;
return rec(sequence, 0, n-1);
}
bool rec(vector<int> & sequence, int start, int end){
if(start >= end) return true;
int root = sequence[end];
int k=start;
while(k < end ){
if(sequence[k] > root)
break;
k++;
}
for(int i=k; i< end; i++){
if(sequence[i]<root)
return false;
}
return rec(sequence, start, k-1) && rec(sequence, k, end-1 );
}
};
P182
二叉树中和为某一值的路径
class Solution {
public:
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
vector<vector<int>> res;
if(!root) return res;
vector<int> v;
rec(root, expectNumber, res, v);
return res;
}
private:
void rec( TreeNode * root, int num, vector<vector<int>> & res, vector<int> & v){
v.push_back(root->val);
num = num - root->val;
if(root->left==NULL && root->right==NULL && num==0 ) {
res.push_back(v);
}
if(root->left){
rec(root->left, num, res, v);
}
if(root->right){
rec(root->right, num, res,v);
}
v.pop_back();
}
};
P187
复杂链表的复制
此题值得思考的点还是挺多的,书中指明了三种方法。
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{ if(pHead == NULL) return NULL;
// step 1: 复制节点
RandomListNode * cur = pHead;
RandomListNode * tmp = NULL;
while(cur){
RandomListNode * newNode = new RandomListNode(cur->label);
tmp = cur->next;
cur->next = newNode;
newNode->next = tmp;
cur = tmp;
}
// step 2: 连接兄弟节点
cur = pHead;
while(cur){
if(cur->random){
cur->next->random = cur->random->next;
}
cur = cur->next->next;
}
// step 3: 拆分链表
cur = pHead;
RandomListNode * res = cur->next;
while(cur){
tmp = cur->next;
cur->next = tmp->next;
if(cur->next == NULL) break; // 这一行要注意加上
tmp->next = cur->next->next;
cur = cur->next;
}
return res;
}
};
P191
二叉搜索树与双向链表
对二叉搜索树中序遍历得到的结果就是从小到大
还是对递归掌握不好
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(pRootOfTree == NULL) return NULL;
TreeNode * pre = NULL;
inOrder(pRootOfTree, pre);
while(pre->left)
pre = pre->left;
return pre;
}
void inOrder( TreeNode * cur, TreeNode * & pre){
if(cur == NULL) return ;
inOrder(cur->left, pre);
cur->left = pre;
if(pre) pre->right = cur;
pre = cur;
inOrder(cur->right, pre);
}
};
P195
序列化二叉树
https://blog.youkuaiyun.com/u011475210/article/details/78889876
个人更倾向字符串的方法,因为树的val的值可正可负
class Solution {
public:
// 本质上就是树的先根遍历
void serializeHelper(TreeNode * cur, string & s){
if(cur==NULL) {
s += "$,";
return ;
}else{
s += to_string(cur->val);
s += ",";
serializeHelper(cur->left,s);
serializeHelper(cur->right,s);
}
}
char* Serialize(TreeNode *root) {
if(!root) return NULL;
string s = "";
serializeHelper(root, s);
char * res = new char[s.length()+1];
strcpy(res, s.c_str());
return res;
}
TreeNode * deserializeHelper(string & s){
if(s[0]=='$'){
s = s.substr(2);
return NULL;
}
TreeNode * res = new TreeNode(stoi(s));
s = s.substr(s.find_first_of(',')+1);
res->left = deserializeHelper(s);
res->right = deserializeHelper(s);
return res;
}
TreeNode* Deserialize(char *str) {
if(!str) return NULL;
string s = str;
return deserializeHelper(s);
}
};
P197
字符串的排列
下面的连接很好,里面是多个排列题目
https://blog.youkuaiyun.com/sinat_33442459/article/details/73732486
牛客网要求按字典序打印,下面通过set做到,同时也考虑了字符可能重复。
class Solution {
public:
vector<string> permutation;
set<string> permutationSet;
void p(string s, int index, int n){
if(index == n-1) {
permutationSet.insert(s);
return ;
}
p(s, index+1,n);
for(int i = index; i < n ;i++){
if(s[i]!=s[index]){
char tmp = s[index];
s[index] = s[i];
s[i] = tmp;
p(s, index+1, n);
tmp = s[index];
s[index] = s[i];
s[i] = tmp;
}
}
}
vector<string> Permutation(string str) {
if(str.length()==0) return permutation;
int n = str.length();
p(str, 0, n);
for(set<string> :: iterator iter = permutationSet.begin(); iter != permutationSet.end(); ++iter ){
permutation.push_back(*iter);
}
return permutation;
}
};
P205
数组中出现次数超过一半的数字
这个题很重要
https://blog.youkuaiyun.com/liangzhaoyang1/article/details/51049237
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
map<int,int> m;
int n = numbers.size();
for(int i=0;i<n;i++)
m[numbers[i]]++;
map<int,int>::iterator iter = m.begin();
while(iter!=m.end()){
if(iter->second > n/2)
return iter->first;
iter++;
}
return 0;
}
};
class Solution {
public:
void partition(vector<int> & numbers, int target, int start, int end){
if(start>=end) return;
int val;
int left = start, right =end;
val = numbers[left];
while(left<right){
while(right>left && numbers[right]>=val)
right--;
if(right > left){
numbers[left] = numbers[right];
left++;
}
while(left<right && numbers[left]<val)
left++;
if(left < right){
numbers[right] = numbers[left];
right--;
}
}
numbers[left] = val;
if(left == target/2) return;
else if( target/2 > left)
partition(numbers, target, left+1,end );
else
partition(numbers, target, start, left-1);
}
int MoreThanHalfNum_Solution(vector<int> numbers) {
int n = numbers.size();
if(n==0) return 0;
int index = n/2;
partition(numbers, index,0,n-1);
int val = numbers[index];
int cnt = 0;
for(int i=0;i<n;i++){
if(numbers[i]==val)
cnt++;
}
if(cnt>index)
return val;
else
return 0;
}
};
P209
最小的k个数
方法一:
时间复杂度O(n log n), 同时原数组也进行了改动
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> res;
int n = input.size();
if(n<k || k<=0) return res;
sort(input.begin(), input.end());
for(int i=0;i<k;i++)
res.push_back(input[i]);
return res;
}
};
方法二:
时间复杂度O(n), 用上一题“数组中出现次数超过一半的数字”的方法,基于partition函数定位到第k大的数字,那么位于左边的就是我们要的结果,注意:得到的这k个数字不一定有序
此外,此方法也修改了输入的数组
可见,快排的思想还是很重要的,很多地方都有用到
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> res;
int n = input.size();
if(n<k || k<=0 || n==0) return res;
if(n==k) return input;
int index;
int start=0, end = n-1;
index = partition(input, start, end);
while(index!= k-1){
if(index > k-1){
end = index-1; //这里要注意
index = partition(input, start, end);
}
else{
start = index+1; // 这里要注意
index = partition(input, start,end);
}
}
for(int i=0;i<k;i++)
res.push_back(input[i]);
return res;
}
private:
int partition(vector<int> & input, int start, int end){
int target = input[start];
while(start<end){
while(start<end && input[end]>target)
end--;
input[start]=input[end];
while(start<end && input[start]<=target)
start++;
input[end]=input[start];
}
input[start]=target;
return start;
}
};
方法三:
时间复杂度O(n log k), `特别适合处理海量数据!!! 只要内存能够容纳leastNumbers即可,因此它最适合的情形就是n很大并且k较小的问题。
C++ multiset通过greater、less指定排序方式,实现最大堆、最小堆功能。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> res;
int len = input.size();
if(len < k || k<=0 ) return res;
multiset<int, greater<int> > leastNumbers;
multiset<int, greater<int>>::iterator iterGreater;
for(int i=0;i<len;i++){
if(leastNumbers.size()<k)
leastNumbers.insert(input[i]);
else{
iterGreater = leastNumbers.begin();
if(input[i] < *iterGreater){
leastNumbers.erase(iterGreater);
leastNumbers.insert(input[i]);
}
}
}
for(iterGreater=leastNumbers.begin();iterGreater!=leastNumbers.end();iterGreater++)
res.push_back(*iterGreater);
return res;
}
};