主要使用c++。
寫代碼時易錯點
-要考慮到特殊輸入并做相應處理,如空指針,空數組等。
題11 旋轉排序數組的最小數字
二分查找 。大體思路是 維護兩個指針,分別指向第一個和最后一個元素。然后找到數組中間的元素,如果這個值大于等于第一個指針指向的元素,那么該中間元素就位于數組中前面遞增的部分,這樣就把前面的指針指向該中間元素。如果這個中間值小于等于后面指針指向的元素,那么該中間值就位于數組中后面遞增的部分,這樣就把后面的指針指向中間元素。這樣不管時移動哪一個指針,查找范圍都會縮小為原來的一半,然后再對更新后的兩個指針做新一輪的查找。最終兩個指針會指向兩個相鄰的元素,而第二個指針正好是指向最小的元素,這就是循環結束的條件。
相關題目 旋轉數組中查找一個數 logN時間
題12 矩陣中的路徑
判斷矩陣中是否存在一條包含某字符串所有字符的路徑。
遞歸實現,回溯法。回溯法非常適合由多個步驟組成的問題,并且每個步驟都有多個選項,當我們在某一步選擇了其中的一個選項時,下一步又面臨新的多個選項。這樣重復選擇直到到達最終的狀態。用回溯法解決的問題的所有選項可以形象的用數狀結構來表示。
程序中都要用一個和原矩陣一樣大的bool矩陣visited來標記每個位置是否被訪問過。
題13 機器人的運動范圍
同題12。
相關題目 在0/1矩陣矩陣中的最大活動范圍。
遍歷每一個元素,每一個元素都可能作為起點。當然,這個時可以再優化的。
程序中都要用一個和原矩陣一樣大的bool矩陣visited來標記每個位置是否被訪問過。
題15 二進制中1的個數
題21 調整數組順序使奇數位于偶數前面
不要求穩定
維護兩個指針,初始化時分別指向第一個和最后一個數字,前面的指針只向后移動,后面的指針只向前移動。在兩個指針相遇之前,第一個指針總是位于第二個指針的前面。如果第一個指針指向的數字為偶數,第二個指針指向的數字為奇數,則交換這兩個數字。
要求穩定
用冒泡排序的思想,復雜度為O(n^2)。
void reOrderArray(vector<int> &array)
{
for(int i = 0;i < array.size();i++)
{
for(int j = array.size()-1; j>i;j--)
{
if(array[j]%2==1&&array[j-1]%2==0)
swap(array[j],array[j-1]);
}
}
}
題22 鏈表中倒數第k個節點
維護兩個指針,讓第一個指向第一節點,另一個指向第k個節點。然后兩個指針同步往后走,當后面的指針走到最后一個節點時,前面的指針正好就走到了倒數第k個節點。
相關問題 求鏈表的中間節點
維護兩個指針,同時從鏈表的頭節點出發,一個指針每次走一步,另一個指針一次走兩步,當走的快的指針走到鏈表的末尾時,走的慢的指針正好走到鏈表的中間。
題23 鏈表中環的入口節點
先確定鏈表中是否存在環,讓兩個指針都從頭節點出發,一個一次走一步,另一個走快些,比如一次走兩步,如果走的快的指針能追上走的慢的指針,那么鏈表中就有環,并且追上時的節點就是環中的節點。然后從這個節點出發一邊往后走一遍計數,再次回到這個節點時,就計數得到環中的節點個數了。環中節點個數設為k,這時鏈表中環的入口節點就相當于鏈表尾節點,同事也是倒數第k個節點。兩指針從頭節點出發,快指針先走k步,然后兩個同步走,當兩個指針相遇時,他們便是到了環的入口節點。
題24 反轉鏈表
思路一 用棧先進后出記住鏈表的順序,比較費內存
把所有節點依次放入一個棧里。最后的節點為要返回的節點,先保存著。然后從棧里每次取出節點,使其指向棧里的下一個節點。
思路二 連續的三個為一組,從前往后走
維護三個指針,分別指向當前要處理的節點、其前一個節點、其后面一個節點,逐步往后走。記住后面一個節點,以防當前節點反轉完后后面的節點找不到了。
題25 合并兩個排序的鏈表
比較合并兩個鏈表的頭節點,使用遞歸
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == nullptr) return pHead2;
else if(pHead2==nullptr) return pHead1;
ListNode* pMergedHead = nullptr;
if(pHead1->val<pHead2->val)
{
pMergedHead=pHead1;
pMergedHead->next=Merge(pHead1->next,pHead2);
}
else
{
pMergedHead=pHead2;
pMergedHead->next=Merge(pHead1,pHead2->next);
}
return pMergedHead;
}
};
相關題目 合并兩個有序數組 參見這里的解法二和解法三
再熟悉下這個,再引申,合并n個有序數組呢
題32 從上倒下打印二叉樹
題33 二叉搜索樹的后序遍歷序列
題34 二叉樹中和為某一值的路徑
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
vector<vector<int>> result;
if(root == nullptr)
return result;
vector<int> path;
int currentSum = 0;
return FindPath( root, expectNumber, path, currentSum,result);
}
vector<vector<int>> FindPath(TreeNode* root, int expectedNumber,vector<int>&path,int currentSum,vector<vector<int>>& result)
{
currentSum += root->val;
path.push_back(root->val);
bool isLeaf = root->left == nullptr && root->right==nullptr;
if(isLeaf && currentSum==expectedNumber)
result.push_back(path);
if(root->left != nullptr)
result = FindPath(root->left,expectedNumber,path,currentSum, result);
if(root->right != nullptr)
result = FindPath(root->right,expectedNumber,path,currentSum, result);
path.pop_back();
currentSum -=root->val;
return result;
}
};
題38 字符串的排列
題39 數組中出現次數超過一半的數字
題40 最小的k個數
題41 數據流中的中位數,這題太難了!
書上的解法中用到了平衡二叉搜索樹,太麻煩艱澀。牛客網上有用優先隊列來做的,優先隊列priority_queue本質也是一個堆。
class Solution {
priority_queue<int, vector<int>, less<int> > p;
priority_queue<int, vector<int>, greater<int> > q;
public:
void Insert(int num){
if(p.empty() || num <= p.top()) p.push(num);
else q.push(num);
if(p.size() == q.size() + 2) q.push(p.top()), p.pop();
if(p.size() + 1 == q.size()) p.push(q.top()), q.pop();
}
double GetMedian(){
return p.size() == q.size() ? (p.top() + q.top()) / 2.0 : p.top();
}
};
題42 連續子數組的最大和
#include<bits/stdc++.h>
using namespace std;
int FindGreatestSumOfSubArray(vector<int> array)
{
int curSum = 0;
int maxSum = array[0];
for(int i = 0;i<array.size();i++)
{
if(curSum<=0)
curSum = array[i];
else
curSum+=array[i];
if(curSum>maxSum)
maxSum = curSum;
}
return maxSum;
}
題47 禮物的最大價值
題51 數組中的逆序對
題52 兩個單向鏈表的第一個公共節點
首先注意,兩個鏈表從第一個公共節點開始,之后的所有節點都是重合的,不可能再出現分叉,其拓撲形狀就像一個Y,而不可能像x。
方法一 使用兩個輔助棧,空間復雜度和時間復雜度都是O(m+n)
分別把連個鏈表的節點放入兩個棧里,這樣兩個鏈表的尾節點就位于兩個棧的棧頂,接下來從兩個棧頂的節點開始依次比較,直到找到最后一個相同的節點。
方法二 不再使用輔助棧,時間復雜度為O(m+n)
先遍歷得到兩個鏈表的長度,得到長的鏈表比短的鏈表多幾個節點。然后在較長的鏈表上先多走這幾個節點。再接下來在兩個鏈表上一起往后走,一直找到第一個相同的節點就是他們的第一個公共節點。
題63 股票的最大利潤
題68 樹中兩個節點的最低公共祖先
關于遞歸的思路,要先想清楚第n級和第n-1級的di
c++常用語法
vector
- 兩個vector相連接,比如在a后面插入b,則為
a.insert(a.end(),b.begin(),b.end())
- vector賦值:
vec2.assign(vec1.begin()+k,vec1.end())
- 截取vec1中的一部分:
vector<int>(vec1.begin()+m,vec.begin()+n)
- vector去重
set<string> st(all_posible.begin(), all_posible.end());
all_posible.assign(st.begin(), st.end());
string
- 截取str的第pos開始的連續len個字母組成的字符串
str.sub(int pos,int len)
,如果第二個參數缺省,則取到最后一個字母。 - str.find(string sub, int i)返回str中第i個位置開始,第一次出現字符串sub的位置。經典例子,求字符串str中出現字符串sub的次數
int fun1(const std::string& str, const std::string& sub)
{
int num = 0;
for (int i = 0; (i = str.find(sub, i)) != std::string::npos; num++, i++);
return num;
}
- 兩字符串相連想,直接
str1+=str2
.
set
- 用別的容器對set進行賦值:```set<string> st(all_posible.begin(), all_posible.end());
#### stack
#### 萬能頭文件
include<bits/stdc++.h>
using namespace std;
## 常用的小知識點
- 錯排公式:D(n)=(n-1)*[D(n-1)+D(n-2)]。[詳解](https://blog.csdn.net/bengshakalakaka/article/details/83420150)