PAT甲級一個月攻略
看看“別人家的程式碼”:
一. 樹
1)求二叉樹的高度(Maximum Depth of Binary Tree)
// LeetCode, Maximum Depth of Binary Tree
// 時間複雜度O(n),空間複雜度O(logn)
class Solution {
public:
int maxDepth(TreeNode *root) {
if (root == nullptr) return 0;
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
};
2)判斷二叉樹是否對稱(Symmetric Tree)
// LeetCode, Symmetric Tree
// 遞迴版,時間複雜度O(n),空間複雜度O(logn)
class Solution {
public:
bool isSymmetric(TreeNode *root) {
return root ? isSymmetric(root->left, root->right) : true;
}
bool isSymmetric(TreeNode *left, TreeNode *right) {
if (!left && !right) return true; // 終止條件
if (!left || !right) return false; // 終止條件
return left->val == right->val // 三方合併
&& isSymmetric(left->left, right->right)
&& isSymmetric(left->right, right->left);
}
};
3)二叉樹-> 連結串列(Flatten Binary Tree to Linked List)
// LeetCode, Flatten Binary Tree to Linked List
// 遞迴版2
// @author 王順達(http://weibo.com/u/1234984145)
// 時間複雜度O(n),空間複雜度O(logn)
class Solution {
public:
void flatten(TreeNode *root) {
flatten(root, NULL);
}
private:
// 把root 所代表樹變成連結串列後,tail 跟在該連結串列後面
TreeNode *flatten(TreeNode *root, TreeNode *tail) {
if (NULL == root) return tail;
root->right = flatten(root->left, flatten(root->right, tail));
root->left = NULL;
return root;
}
};
二. 字串
1)最長無重複字元子串(Longest Substring Without Repeating Characters)
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int ans = 0;
int dic[256];
memset(dic,-1,sizeof(dic));
int len = s.size();
int idx = -1;
for (int i=0;i<len;i++)
{
char c = s[i];
if (dic[c]>idx)
idx = dic[c];
ans = max(ans,i-idx);
dic[c] = i;
}
return ans;
}
};
三. 陣列
1)陣列中所有數字出現兩次,只有一個出現一次,求出它(Single Number)
// LeetCode, Single Number
// 時間複雜度O(n),空間複雜度O(1)
class Solution {
public:
int singleNumber(int A[], int n) {
int x = 0;
for (size_t i = 0; i < n; ++i)
x ^= A[i];
return x;
}
};
2)順時針旋轉二維陣列90度(Rotate Image)
// LeetCode, Rotate Image
// 思路1,時間複雜度O(n^2),空間複雜度O(1)
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
const int n = matrix.size();
for (int i = 0; i < n; ++i) // 沿著副對角線反轉
for (int j = 0; j < n - i; ++j)
swap(matrix[i][j], matrix[n - 1 - j][n - 1 - i]);
for (int i = 0; i < n / 2; ++i) // 沿著水平中線反轉
for (int j = 0; j < n; ++j)
swap(matrix[i][j], matrix[n - 1 - i][j]);
}
};
3)排序陣列去重(Remove Duplicates from Sorted Array)
// LeetCode, Remove Duplicates from Sorted Array
// 時間複雜度O(n),空間複雜度O(1)
class Solution {
public:
int removeDuplicates(int A[], int n) {
if (n == 0) return 0;
int index = 0;
for (int i = 1; i < n; i++) {
if (A[index] != A[i])
A[++index] = A[i];
}
return index + 1;
}
};
4)兩個排序陣列,求中位數(Median of Two Sorted Arrays)
// LeetCode, Median of Two Sorted Arrays
// 時間複雜度O(log(m+n)),空間複雜度O(log(m+n))
class Solution {
public:
double findMedianSortedArrays(int A[], int m, int B[], int n) {
int total = m + n;
if (total & 0x1)
return find_kth(A, m, B, n, total / 2 + 1);
else
return (find_kth(A, m, B, n, total / 2)
+ find_kth(A, m, B, n, total / 2 + 1)) / 2.0;
}
private:
static int find_kth(int A[], int m, int B[], int n, int k) {
//always assume that m is equal or smaller than n
if (m > n) return find_kth(B, n, A, m, k);
if (m == 0) return B[k - 1];
if (k == 1) return min(A[0], B[0]);
//divide k into two parts
int ia = min(k / 2, m), ib = k - ia;
if (A[ia - 1] < B[ib - 1])
return find_kth(A + ia, m - ia, B, n, k - ia);
else if (A[ia - 1] > B[ib - 1])
return find_kth(A, m, B + ib, n - ib, k - ib);
else
return A[ia - 1];
}
};
////////////////////////////////////////////////
處理大數問題:
1.http://blog.csdn.net/hacker00011000/article/details/51298294
2.http://blog.csdn.net/nk_test/article/details/48912763
algorithm中常用的現成演算法:
1.binary_search() 確定容器中是否存在某個元素
2.equal() 確定兩個集合中的所有元素皆相同。
3.lower_bound() 從頭到尾,查詢第一個大於或者等於所列元素的值的位置
用法,參考下面的min_element();
4.upper_bound() 從頭到尾,查詢第一個大於所列元素的值的位置
5.make_heap( ) 建立一個堆並以序列的形式輸出
6.max() 返回兩個元素間的較大者
7.max_element() 返回序列中的最大值
8.min() 返回兩個元素中的較小者
9.min_element() 返回序列中的最小值
int a[]={1,4,66,43,2,56,443,23,234,4};
int b= min_element(a,a+7)-a;
int c= max_element(a,a+7)-a;
如果想取值的話,直接加*
: *max_element(a,a+n)
10.mismatch() 查詢兩個序列中的第一個不相同的位置
11.pop_heap() 從一個堆中移除一個最大的元素
12.push_heap() 新增一個元素至堆
13.reverse() 將給定序列反轉順序,範圍。
14.sort() 將序列升序排序
15.sort_heap() 將堆轉變為有序序列
16.swap() 交換兩個物件的值
17.unique() 移除連續的重複元素
注意連續兩個字,也就是說明了要先進性排序操作
為什麼呢?
因為unique函式並沒有把重複的元素刪掉,他只是把那些重複的元素移動
到了本序列的末尾,
返回值是不重複序列的位置指標。
所以如何顯示不重複序列呢?
1.一種方法是直接將不重複序列指標 it 到 vector.end()
對此階段進行 刪除
用erase()函式
erase(it,vector.end());
2.直接將vector.begin 到不重複序列尾的 位置指標 it 將元素輸出來
即,
vector<int>::iterator it=a.begin();
while(it!= unique(a.begin(),a.end()))
{
cout<<*it<<" ";
it++;
}
VECTOR_STRING::iterator iNameTor;
iNameTor = unique(vecNames.begin(), vecNames.end());
cout << "after unique(), contents are:" << endl;
printVec(vecNames);
cout << "unique return a iterator, point to the first Duplicate element " << endl;
cout << iNameTor - vecNames.begin() << endl << endl;
vecNames.erase(iNameTor, vecNames.end()); //刪除重複元素
cout << "after erase(), contents are:" << endl;
18. 輸入:多行資料:每行資料之間空格間隔,
輸出:對應的行,每行輸出對應行的所有數字之和。
程式設計:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string line;
while(getline(cin,line))
{
int sum=0,x;
stringstream ss(line);
while(ss>>x)
{
sum+=x;
}
cout<<sum<<endl;
}
return 0;
}
忘了題的話,詳見演算法競賽104頁。
19.
strlwr()將字串變小寫
strupr()將字串變大寫
strcmp()兩個引數只能是c字串,不能是string型別,也可以用s.data()
20. C++容器類常用泛型函式總結
Functions in <algorithm>
count()函式的一個例子:
// count algorithm example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main () {
int mycount;
// counting elements in array:
int myints[] = {10,20,30,30,20,10,10,20}; // 8 elements
mycount = (int) count (myints, myints+8, 10);
cout << "10 appears " << mycount << " times.\n";
// counting elements in container:
vector<int> myvector (myints, myints+8);
mycount = (int) count (myvector.begin(), myvector.end(), 20);
cout << "20 appears " << mycount << " times.\n";
return 0;
}
find()函式的一個例子:
InputIterator find ( InputIterator first, InputIterator last, const T& value );
// find example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main () {
int myints[] = { 10, 20, 30 ,40 };
int * p;
// pointer to array element:
p = find(myints,myints+4,30);
++p;
cout << "The element following 30 is " << *p << endl;
vector<int> myvector (myints,myints+4);
vector<int>::iterator it;
// iterator to vector element:
it = find (myvector.begin(), myvector.end(), 30);
++it;
cout << "The element following 30 is " << *it << endl;
return 0;
}
find_first_of()的例子
// find_first_of example
#include <iostream>
#include <algorithm>
#include <cctype>
#include <vector>
using namespace std;
bool comp_case_insensitive (char c1, char c2) {
return (tolower(c1)==tolower(c2));
}
int main () {
int mychars[] = {'a','b','c','A','B','C'};
vector<char> myvector (mychars,mychars+6);
vector<char>::iterator it;
int match[] = {'A','B','C'};
// using default comparison:
it = find_first_of (myvector.begin(), myvector.end(), match, match+3);
if (it!=myvector.end())
cout << "first match is: " << *it << endl;
// using predicate comparison:
it = find_first_of (myvector.begin(), myvector.end(),
match, match+3, comp_case_insensitive);
if (it!=myvector.end())
cout << "first match is: " << *it << endl;
return 0;
}
reverse()實現逆轉
reverse_copy()實現逆轉,不改變原來的字串
sort()
unique()
erase()
repalce()
replacse_copy()
不改變原來的字串或者是容器的內容
strlwr()將字串變小寫
strupr()將字串變大寫
strcmp()兩個引數只能是c字串,不能是string型別,也可以用s.data()
template <class T> const T& max ( const T& a, const T& b );
template <class T, class Compare>
const T& max ( const T& a, const T& b, Compare comp );
find_if()函式的例子:
// find_if example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool IsOdd (int i)
{
return ((i%2)==1);
}
int main () {
vector<int> myvector;
vector<int>::iterator it;
myvector.push_back(10);
myvector.push_back(25);
myvector.push_back(40);
myvector.push_back(55);
it = find_if (myvector.begin(), myvector.end(), IsOdd);
cout << "The first odd value is " << *it << endl;
return 0;
}
map容器的操作:
begin()返回指向第一個元素的迭代器
end()返回指向最後一個元素的迭代器
rbegin()返回指向最後一個元素的迭代器
rend()返回指向第一個元素的迭代器
empty()測試map容器是不是空的
size()返回容器的大小
max_size()返回容器最大的容量,這個是相對於記憶體來講的
insert()向容器中插入元素
erase(it)刪除容器當中it指向的元素,it為迭代器
erase('c')刪除容器中鍵值為'c'的元素
eras(it, mymap.end())刪除容器中it和mymap.end()之間的元素,它們兩個都是迭代器
foo.swap(bar)交換容器foo和bar中的元素
clear()清空容器
find('b')返回指向鍵值為'b'的的迭代器,沒有的話就指向end()
count('c')查詢鍵值為'c'的元素,在map中返回0或者1,0表示沒有這個鍵值,1表示有,但是在mutimap中就是這個鍵值出現的次數
lower_bound('b')返回指向鍵值為'b'的迭代器,當沒有這個鍵值時就返回空的迭代器
upper_bound('b')返回指向鍵值為'b'的下一個元素的迭代器,沒有的話就返回空的迭代器
vector容器的操作:
begin()返回指向第一個元素的迭代器
end()返回指向最後一個元素的迭代器
rbegin()返回指向最後一個元素的迭代器
rend()返回指向第一個元素的迭代器
size()返回容器的元素的個數
max_size()返回容器的最大的元素的個數
resize()重新調整容器的容量,無論原來的容量是大於還是小於後來的惡容量都可以
myvector.resize(5);將容器的容量調整為5,如果變短了就直接刪除多餘的元素,長了就用0將剩餘的空間填滿
myvector.resize(8,100);將容器的容量調整8,並將多出來的位置用100表示
myvector.resize(12);將容器的容量調整為12,多出的空間用0填充
capacity()返回這個容器在記憶體空間中最多的連續空間
empty()測試這個容器是不是空的
reserve()重新調整容器的capacity
at(i)返回位置為i處得元素的引用,當超出容器的最後一個位置就丟擲一個異常
front()返回第一個元素的引用
back()返回最後一個元素的引用
void assign ( InputIterator first, InputIterator last );將迭代器first和迭代器last之間的元素付給呼叫這個方法的容器
void assign ( size_type n, const T& u );將n個u付給容器
push_back()在容器的末尾新增元素
pop_back()刪除容器最後面的一個元素
iterator insert ( iterator position, const T& x );在迭代器position的前面插入元素x
void insert ( iterator position, size_type n, const T& x );在position的前面插入n個x
template <class InputIterator>
void insert ( iterator position, InputIterator first, InputIterator last );將迭代器first和last之間的元素插入到position前面
iterator erase ( iterator position );刪除迭代器position指向的元素
iterator erase ( iterator first, iterator last );刪除迭代器first和last之間的元素,不包括last指向的元素
void swap ( vector<T,Allocator>& vec );交換兩個容器的元素
void clear ( );清空容器當中的元素
set容器(只儲存值不相同的元素,並且按照從小到大的順序排列)
iterator begin ();返回指向set容器第一個元素的迭代器
iterator end ();返回指向容器最後一個元素的迭代器
reverse_iterator rbegin();返回指向容器最後一個元素的迭代器
reverse_iterator rend();返回指向容器第一個元素的迭代器
bool empty ( ) const;測試容器是否為空
size_type size() const;計算容器當中元素的個數
size_type max_size () const;計算容器的最大容量
pair<iterator,bool> insert ( const value_type& x );將元素x插入到set容器中返回pair物件,first元素為指向插入的元素的迭代器,second元素為指示插入成功與否的bool值
iterator insert ( iterator position, const value_type& x );將x插入
template <class InputIterator>
void insert ( InputIterator first, InputIterator last );將first與last只見到惡元素插入到容器中
void erase ( iterator position );刪除position位置處得元素
size_type erase ( const key_type& x );刪除值為x的元素
void erase ( iterator first, iterator last );刪除迭代器first和last之間的元素
void swap ( set<Key,Compare,Allocator>& st );交換兩個set容器的元素
void clear ( );清空set容器
容器迭代器的操作
stack棧的操作:
bool empty ( ) const;測試棧是不是空的返回1表示空0表示非空
size_type size ( ) const;返回當前棧的元素的個數
value_type top ( );返回當前的棧頂元素,不刪除這個元素
const value_type top ( ) const;返回棧頂元素的const引用
void push ( const T& x );將當前的元素x入棧
void pop ( );刪除棧頂元素
queue佇列的操作:
bool empty ( ) const;測試當前佇列是不是空,0表示空,1表示非空
size_type size ( ) const;佇列的元素的個數
value_type& front ( );返回隊首元素的引用
const value_type front ( ) const;返回隊首元素的const值
value_type& back ( );返回隊尾元素的引用
const value_type& back ( ) const;返回隊尾元素的const值
void push ( const T& x );將x入佇列
void pop ( );刪除隊首元素
string型別的應用
string.c_str() 返回的是const char*而非char *,如果想返回char *的話可以這樣寫:char * a = (char*)string.c_str();
strtok()函式很好用,分割字串
還有一個大優勢,就是容器之間可以直接賦值。
或許還有其他的操作符被過載了,這個看具體情況。
set:
就是數學意義上的集合——每個元素最多隻出現一次。
字元大小寫轉換函式:
tolower(char c)函式,tolower()函式的引數是字元型別。
toupper(char c)函式,toupper()函式的引數也是字元型別。
字串大小寫轉換:
c中,包含ctype.h標頭檔案
:
strlwr()將字串變小寫
strupr()將字串變大寫
strcmp()兩個引數只能是c字串,不能是string型別,也可以用s.data()
c++,中,tolower()、toupper()配合transform()函式
程式設計:
1.下面的程式設計 是改變發生在原字串S上。
#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>
using namespace std;
int main()
{
string s="Hello worLD";
transform(s.begin(),s.end(),s.begin(),::toupper);
cout<<s<<endl;
transform(s.begin(),s.end(),s.begin(),::tolower);
cout<<s<<endl;
return 0;
}
2.下面的程式設計是 改變發生在新建字串c上,不過有一條語句十分的重要
#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>
using namespace std;
int main()
{
string s="Hello worLD";
string c;
c.resize(s.size());
transform(s.begin(),s.end(),c.begin(),::toupper);
cout<<c<<endl;
transform(s.begin(),s.end(),c.begin(),::tolower);
cout<<c<<endl;
return 0;
}
。
20.有權圖的單源最短路徑問題:
迪傑斯特拉 演算法:
針對常見問題、疑惑給出的結論:
若路徑是按照遞增(非遞減)的
順序生成的,則:
1.真正的最短路必須只經過S中的頂點
2.每次從未收錄的頂點中選一個dist值最小的收錄(貪心)
3.增加一個v進入S,可能影響另外一個w的dist值。
而且針對第3點,還有一個重要的說明就是v如果能夠改變w
也有一個必要條件,就是v和w一定是鄰接點。
這樣程式設計就好編了。
dist[w] = min{dist[w],dist[v]+<v,w>的權重}。
22.倒計時一個月:
資料輸入範圍:
int 記住絕對值在10^9 範圍以內的整數都可以定義為 int 。
long long 記住 在10^10 ~10^18 範圍以內的整數都可以定義為 long long 。
long long bignum = 123456789012345LL;
需要 加 LL 。
見 《演算法筆記》 P8.、
如果陣列大小較大,大概10^6 級別,則需要將其定義在主函式的外面,
否則會使程式異常退出。
**不使用 float ,都使用 double .**
**無窮大INF的定義:**
const int INF = (1<<30)-1;
const int INF = 0x3fffffff;
**常用數學函式:**
fabs(double x)
:對double型別變數取絕對值。
floor(double x)
: 對double 型別變數向下取整
ceil(double x)
: 對double 型別變數向上取整
pow(double x,double y)
: 求 x^y
sqrt(double x)
: 對double 型別變數求算術平方根。
log(double x)
: 對double 型別變數求以自然對數為底的對數。
round(double x)
: 對double 型別變數x進行四捨五入。
**對氣泡排序的簡單思考:**
從陣列 前到後 遍歷,交換 -》》》沉底演算法;
從陣列 後到前 遍歷,交換 -》》》冒泡演算法。
memset():
--對陣列中的每一個元素賦一個相同的值。
包含標頭檔案 #include <cstring>
注意:
**對於初學者,只建議使用memset賦 0 或 -1;
如果要對陣列賦其他數字,比如1,使用 fill()函式。
這裡已經試過了,的確賦其他值,比如 34 的時候,出錯了。
這裡一定要注意一下。**
**判斷字元是字母,數字,還是字母數字,以及大寫,小寫:**
2.cctype中還有其他函式,如:
isdigit() 用來判斷一個字元是否是數字。
isalnum() 用來判斷一個字元是否為英文字母或數字,相當於 isalpha(c) || isdigit(c)
isalpha() 用來判斷一個字元是否是英文字母,相當於 isupper(c)||islower(c)
**建構函式有什麼用呢?**
初始化,就記住初始化就可以了。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
struct Point{
int x;
Point(){
}
};
int main()
{
Point a;
return 0;
}
**永遠保持有一個預設的空的建構函式,這樣我們在宣告一個
自定義型別變數的時候,就可以不必初始化**。詳見 演算法筆記》P73.
sscanf()和sprintf()
:流輸入輸出函式,這個東西很有用,尤其是sscanf,可以實現一次性的多個分割:
比如:
將字元陣列str中的內容按 "%d:%lf,%s"的格式
寫到int型變數n、double型變數db、char型陣列變數str2中。
sscanf(str,"%d:%lf,%s",&n,&db,&str2);
相對應的反操作:
sprintf(str,"%d:%lf,%s",n,db,str2);
補充內容:
1.cin、cout P74
2.浮點數的比較 P75
const double eps=1e-8;
#define Equ(a,b) ( (fabs( (a)-(b) )) <(eps) )
3.圓周率
const double PI=acos(-1.0);
4.複雜度 P78
**剛才在做題過程中除錯發現問題,結果是因為pow()函式。**
首先你應該知道,需要使用 pow 函式,
你需要加上 #include<math.h>,雖然這個不是問題所在,
但是是一個好習慣。在 math.h 中,或者查閱相關 C 語言的手冊,
你會發現,pow 函式的原型是 double pow( double, double ),
查函式的原型也是一個好習慣;所以你知道了,傳入 pow 函式的應該是一個浮點數。
**在極個別奇葩編譯器中,因為浮點數的表示問題,
10 會被表示為 9.99999999999,所以 10 的 4 次方就是 9999.9999……,
double 轉成 int 的時候截斷,所以剩下了 9999。不過,**
據說這個極個別的情況只在一些低版本的 mingw 中才存在,
詳細問題可以看演算法筆記 P87 對應codeup的 6170 部分A+B
25.進位制轉換:
**其他進位制轉換為 10 進位制,用while()迴圈;
10 進位制轉換為 其他k進位制,就是除k取餘法,用do {}while;**
26.單點測試的技巧:
巧妙地利用EOF , 演算法筆記 P97
PAT B 的經典說反話 。
27.基本的排序演算法:
1.選擇排序:
每次從未排序的序列中選擇最小的數,然後將其與未排序的序列第一個元素交換,
並與之前已經排好序的序列,自動形成有序序列。
貼到已排序的序列屁股後面。
2.歸併排序:
過程就是從2人小組/1人小組,N/2個小組,到四人小組,N/4個小組,一直到N人小組,1個小組。
歸併就是把兩個有序的序列合併為一個有序的序列的過程。
總之算是分治與歸併的結合就是歸併排序,可以看下面的程式碼:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <sstream>
#include <cmath>
#include <vector>
using namespace std;
const int maxn=100;
void merge(int a[],int L1,int R1,int L2,int R2)
{
int i=L1,j=L2;
int temp[maxn];
int index=0;
while(i<=R1 && j<=R2)
{
if(a[i]<=a[j])
{
temp[index++]=a[i++];
}
else
{
temp[index++]=a[j++];
}
}
while(i<=R1)
{
temp[index++]=a[i++];
}
while(j<=R2)
{
temp[index++]=a[j++];
}
for(int i=0;i<index;i++)
{
a[L1+i]=temp[i];
}
}
void merge_sort(int a[],int left,int right)
{
if(left<right)
{
int mid= (left+right)/2;
merge_sort(a,left,mid);
merge_sort(a,mid+1,right);
merge(a,left,mid,mid+1,right);
}
}
int main()
{
int a[]={4,5,3,3,2,3,7,8,2,1};
for(int i=0;i<sizeof(a)/sizeof(int);i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
merge_sort(a,0,9);
for(int i=0;i<sizeof(a)/sizeof(int);i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}
3.快速排序
其實也沒什麼,就是每次挑出一個數(通常選相對第一個數),作為中間的“裁判”,劃分左右部分的過程。
具體的細節可能需要注意。
比如元素的序號是從1~N的,存放在A[]中。 我們首先把A[1]元素值提取出,存放在臨時變數temp
中,這樣,
所以利用two pointers 思想,left指標指向A[1]位置,right指標指向A[N],然後我們注意,先動的,是right指標。
只能向左移動了,但是動之前需要先判斷**。
首先判斷A[N]是否小於等於temp變數,如果滿足條件,就把A[N]元素與A[1]元素交換,還是注意,
**A[1]元素的值是無關緊要的,因為我們早已經用temp變數儲存了下來。但是交換之後,也就意味著A[N]元素的值變成無關緊要的,
我們不能對A[1]隨便修改了,
因為此時儲存 原來A[N]元素的關鍵人物,只有A[1]了,如果我們再對它一不小心進行了別樣的修改,也就是講一個沒有額外備份的元素銷燬,它將灰飛煙滅。**
所以接下來該怎麼辦呢?繼續移動指標並進行判斷。
那麼移動left還是right呢?判斷什麼呢?
並將其原來的位置作為下一個可以繼續我們“蹂躪”的位置。
而A[N]的位置顯然是在最右邊的。移動什麼呢?
只能是移動left指標了。
將left指標向右移動,直到出現A[i]元素大於temp的時候,就將A[i]元素與A[N]元素互換,此時,無關緊要的位置又變成了A[i],就這樣迴圈下去。直到left指標和right指標相遇。
也就是
所以這只是一次,以A[1]作為裁判劃分出了“大致有序”的左半部分和右半部分。我們還需要分別對左右兩邊繼續實行同樣的策略。
我這裡所謂的“大致有序”,就是以“裁判”為準,左邊部分都是小於裁判的元素,右邊部分都是大於裁判的元素,但是左邊部分不保證有序,右邊部分也不保證有序。
這也是還需要對左邊部分和右邊部分分別進行同樣的以上操作的必要原因。
總結一下,關鍵點:
1.two pointers;
2.分治,遞迴;
3.其實我覺得很關鍵的,反倒是一個臨時變數temp,儲存“裁判”元素,也就是意味著,
原來的陣列A[]多出了一個“無關緊要”的,我們可以任意移動的元素位置,利用這一點,就好像踢皮球一樣,左一腳右一腳。
直到裁判元素的位置最終確定。
28.容器的排序
在STL容器中,只有vector 、string 、deque是可以使用sort的。
30.C++中容器遍歷的5種方式:
std::vector是我在標準庫中實用最頻繁的容器。總結一下在遍歷和建立vector時需要注意的一些地方。
在不考慮執行緒安全問題的前提下,在C++11中有五種遍歷方式。
方式一
for (size_t i =0; i < vec.size(); i ++) {
int d = vec[i];
}
方式二
size_t len = vec.size();
for (size_t i =0; i < len; i ++) {
int d = vec[i];
}
方式三
for (auto it = vec.begin(); it != vec.end(); it ++) {
int d = *it;
}
方式四
for (int i:vec) {
int d = i;
}
方式五
for_each(vec.begin(), vec.end(), [](int i){
int d = i;
});
31.但是要注意
vector<int> vec;
for (auto i:vec) {
printf("%d ",i);
}
**簡便寫法,這裡實際上是進行了值傳遞,就是一份拷貝,如果是需要更改
原來的資料,需要改成引用的形式**,
vector<int> vec;
int d=0;
for (auto& i:vec) {
i= d;
}
32. string 的小技巧:
string a="abcdeffdfsfsd";
**string b=string(a,5);**
cout<<b;
最終輸出的是:ffdfsfsd
自己截取了。
33. 讀取一行字串的時候,如何不摻雜其他的‘,’等符號時,可以直接利用EOF:
比如: HELLO WORLD I AM HERE
char s[90][90];
int num=0;
while( scanf("%s",s[num])!=EOF )
{
num++;
}
但是如果還有其他混淆字元等時,就需要過濾:
比如:
string line;
getline(cin,line);
while(!isalnum(line[i]))
{
i++;
}
**然後就是對非空字元進行判斷處理,比如說進MAP容器中,等。**
string word="";
while(isalnum(line[i]))
{
word+=line[i];
i++;
}
if(word!="")
{
...
}