多种排序算法
快排
//快排
void quickSort(int *array,int left,int right) {
if (left < right) {
int pivot = array[left];
int low = left, high = right;
while (low < high) {
while (low < high && array[high] > pivot) {
--high;
}
array[low] = array[high];
++low;
while (low < high && array[low] < pivot) {
++low;
}
array[high] = array[low];
--high;
}
array[low] = pivot;
quickSort(array,left,low-1);
quickSort(array,low+1,right);
}
}
归并排序
void merge(int *data,int start,int end,int *result) {
int mid = start + ((end-start)>>1);
int l = start, r = mid + 1;
int cur = start;
while (l <= mid && r<=end) {
if (data[l] <= data[r]) {
result[cur] = data[l];
++l;
}
else {
result[cur] = data[r];
++r;
}
++cur;
}
while (l <=mid) {
result[cur] = data[l];
++cur;
++l;
}
while (r<=end) {
result[cur] = data[r];
++r;
++cur;
}
for (int i = start; i <= end; ++i) {
data[i] = result[i];
}
}
//归并排序
void merge_sort(int *data,int start,int end,int *result) {
if (1 == end - start) { //只有两个元素
if (data[start] > data[end]) {
swap(data[start],data[end]);
}
return;
}
else if (end == start)
return;
else {
int mid = start + ((end - start) >> 1);
//cout << start << " " << mid << " " << end << endl;
merge_sort(data,start,mid,result);
merge_sort(data,mid+1,end,result);
merge(data,start,end,result);
}
}
字符串相关
给定一个字符串,找到第一个不重复的字符 时间复杂度为 O(N) 空间复杂度为O(1)
char findFirstSoloChar(string &str) {
vector<int> showTime(128,0);
for (int i = 0; i < str.size();++i) {
++showTime[str[i]];
}
for (int i = 0; i < str.size();++i) {
if (showTime[str[i]] == 1) {
cout << str[i] << endl;
return str[i];
}
}
}
KMP算法 (字符串匹配)
void computerPredix(string &m, vector<int> &prdx) {
int mlen = m.size();
prdx[0] = 0;
int k = 0;
for (int i = 1; i < mlen; ++i) {
while (k > 0 && m[k] != m[i]) {
k = prdx[k] < 2 ? 0 : prdx[k] - 2;
}
if (m[i] == m[k])
k = k + 1;
prdx[i] = k;
}
}
//计算mtc串在s中出现的次数
int KMP(string &s,string &mtc) {
int slen = s.size();
int mlen = mtc.size();
vector<int> predix(mlen);
computerPredix(mtc,predix);
int midx = 0;
int cntMtc = 0;
for (int i = 0; i < slen;++i) {
while (midx > 0 && mtc[midx] != s[i]) {
midx = predix[midx];
}
if (mtc[midx] == s[i])
++midx;
if (midx == mlen) {
++cntMtc;
cout << "匹配" << cntMtc << "次" << endl;
midx = 0;
}
}
return cntMtc;
}
最长公共子串匹配
动态规划,子串要求是连续的,所以只有在 i== j的时候才更新 dp[i][j] = dp[i-1][j-1]+1
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
string LCS(string str1, string str2) {
// write code here
if("" == str1 || "" == str2) return "";
int curl=-1,curr = -1;
int bestLen = 0,bestr = -1;
int len1 = str1.size();
int len2 = str2.size();
vector<vector<int>> dp(len1,vector<int>(len2,0));
for(int i=0;i<len1;++i){
if(str1[i] == str2[0]) {
dp[i][0] = 1;
bestr = i;
bestLen = 1;
}
}
for(int i=0;i<len2;++i){
if(str1[0] == str2[i]) {
dp[0][i] = 1;
bestr = 0;
bestLen = 1;
}
}
for(int i=1;i<len1;++i){
for(int j=1;j<len2;++j){
if(str1[i] == str2[j]) dp[i][j] = dp[i-1][j-1]+1;
if(dp[i][j] > bestLen) {
bestr = i;
bestLen = dp[i][j];
}
}
}
return str1.substr(bestr+1-bestLen,bestLen);
}
前缀树
struct PredixTree {
int pass; //经过了几次
int end; //以此节点为叶节点的个数
vector<PredixTree*> subTree;
PredixTree() :pass(0), end(0), subTree(vector<PredixTree*>(26, nullptr)) {
}
};
class Solution {
public:
/**
*
* @param operators string字符串vector<vector<>> the ops
* @return string字符串vector
*/
PredixTree *root;
Solution() { root = new PredixTree(); }
~Solution() { delete root; }
vector<string> trieU(vector<vector<string> >& operators) {
// write code here
int opLen = operators.size();
vector<string> res;
if (opLen < 1) return res;
for (int i = 0; i < opLen; ++i) {
string op = operators[i][0];
string word = operators[i][1];
if (op == "1") {//1 添加
addWord(root, word);
}
else if (op == "2") {//2 删除
if (isInPreTree(root, word))
delWord(root, word);
}
else if (op == "3") { //3 查询
if (isInPreTree(root, word))
res.push_back("YES");
else
res.push_back("NO");
}
else if (op == "4") {//4 以word为前缀的单词数量
int cnt = getWordCnt(root, word);
res.push_back(to_string(cnt));
}
}
return res;
}
//向前缀树中添加单词
void addWord(PredixTree* root, string &word) {
PredixTree *rc = root;
for (int i = 0; i < word.size(); ++i) {
(rc->pass)++;
if (rc->subTree[word[i] - 'a'] != nullptr) {
rc = rc->subTree[word[i] - 'a'];
}
else {
rc->subTree[word[i] - 'a'] = new PredixTree();
rc = rc->subTree[word[i] - 'a'];
}
}
(rc->pass)++;
(rc->end)++;
}
//删除word
void delWord(PredixTree* root, string &word) {
PredixTree *rc = root;
int n = word.size();
int i = 0;
for (; i < n; ++i) {
(rc->pass)--;
if ((rc->subTree[word[i] - 'a']->pass) == 1) {
PredixTree *tmp = rc->subTree[word[i] - 'a'];
rc->subTree[word[i] - 'a'] = nullptr;
rc = tmp;
++i;
break;
}
rc = rc->subTree[word[i] - 'a'];
}
(rc->pass)--;
if (rc->pass > 0) {
rc->end--;
return;
}
while (i < n) {
PredixTree *next = rc->subTree[word[i]-'a'];
delete rc;
rc = next;
++i;
}
if (i == n) {
delete rc;
return;
}
}
//是否在前缀树中
bool isInPreTree(PredixTree* root, string &word) {
PredixTree *rc = root;
for (int i = 0; i < word.size(); ++i) {
if (rc->subTree[word[i] - 'a'] == nullptr) return false;
else
rc = rc->subTree[word[i] - 'a'];
}
return true;
}
//获得单词的数量
int getWordCnt(PredixTree* root, string &word) {
PredixTree *rc = root;
for (int i = 0; i < word.size(); ++i) {
if (rc->subTree[word[i] - 'a'] == nullptr) return 0;
else
rc = rc->subTree[word[i] - 'a'];
}
return rc->pass;
}
};
链表
合并两个有序链表
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(nullptr == l1) return l2;
if(nullptr == l2) return l1;
ListNode *headPre = new ListNode();
ListNode *newHead = headPre;
ListNode *h1 =l1,*h2 = l2;
while(h1 != nullptr && h2 != nullptr){
if(h1->val < h2->val){
newHead->next = h1;
h1 = h1->next;
}else{
newHead->next = h2;
h2 = h2->next;
}
newHead = newHead->next;
newHead->next = nullptr;
}
if(h1 != nullptr) newHead->next = h1;
if(h2 != nullptr) newHead->next = h2;
newHead = headPre->next;
delete headPre;
return newHead;
}
反转单链表
ListNode* reverseList(ListNode* head) {
if(nullptr == head || nullptr == head->next)
return head;
ListNode *pre = nullptr;
ListNode *cur = head;
while(cur != nullptr){
ListNode *tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
反转给定区间的单链表
ListNode* reverseBetween(ListNode* head, int left, int right) {
if(nullptr == head || nullptr == head->next) return head;
if(left >= right) return head;
ListNode *leftPre = nullptr;
ListNode *leftNode = head;
ListNode *rightNode = nullptr;
ListNode *rightNext = nullptr;
int curPos = 1;
ListNode *hc = head;
while(hc != nullptr){
if(curPos == (left-1)){
leftPre = hc;
leftNode = hc->next;
}
if(curPos == right){
rightNode = hc;
rightNext = hc->next;
break;
}
hc = hc->next;
++curPos;
}
ListNode *pre = leftNode;
ListNode *cur = leftNode->next;
while(cur!= nullptr && cur != rightNext){
ListNode *tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
leftNode->next = rightNext;
if(left == 1) return rightNode;
leftPre->next = rightNode;
return head;
}
判断链表是否是回文
如果只需要链表的前半部分,通常都用快慢指针
bool isPalindrome(ListNode* head) {
if(nullptr == head || nullptr == head->next) return true;
ListNode *low = head;
ListNode *fast = head;
stack<int> preHalf;
while(fast && fast->next){
preHalf.push(low->val);
low = low->next;
fast = fast->next->next;
}
if(fast && (fast->next == nullptr)) low = low->next;
while(low){
if(low->val != preHalf.top()) return false;
low = low->next;
preHalf.pop();
}
return true;
}
如何判断两个链表是否相交
数组
一个长度为n的整型数组,数组中的每个元素的取值范围为[0,n-1],判断该数组是否有重复的数
int findRepeatNumber(vector<int>& nums) {
//最简单的方法 hash
//vector<bool> isExis(nums.size(),false);
int n = nums.size();
if(n<1) return -1;
//for(int i=0;i<n;++i){
// if(isExis[nums[i]]) return nums[i];
// else
// isExis[nums[i]] = true;
//}
//return -1;
//在原数组上进行更改
for(int i=0;i<n;++i){
if(nums[i] == i) continue;
else if(nums[nums[i]] == nums[i]) return nums[i];
else
swap(nums[i],nums[nums[i]]);
}
return -1;
}
二叉树
层次遍历
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(nullptr == root) return res;
TreeNode* rc = nullptr;
deque<TreeNode*> dq;
dq.push_back(root);
int counts = 1; //下一层的节点数目
while(!dq.empty()){
vector<int> levelE;
int tmpC = 0;
while(counts--){
rc = dq.front();
dq.pop_front();
levelE.push_back(rc->val);
if(nullptr != rc->left){
++tmpC;
dq.push_back(rc->left);
}
if(nullptr != rc->right){
++tmpC;
dq.push_back(rc->right);
}
}
res.push_back(levelE);
counts = tmpC;
}
return res;
}
前序、中序、后序遍历(非递归)
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param root TreeNode类 the root of binary tree
* @return int整型vector<vector<>>
*/
vector<vector<int> > threeOrders(TreeNode* root) {
// write code here
vector<vector<int>> res;
if(nullptr == root) return res;
vector<int> ele = preOrder(root);
res.push_back(ele);
ele = midOrder(root);
res.push_back(ele);
ele = postOrder(root);
res.push_back(ele);
return res;
}
vector<int> preOrder(TreeNode* root){
vector<int> res;
//用栈
TreeNode* rc = root;
stack<TreeNode* > st;
while(root || !st.empty()){
if(root){
res.push_back(root->val);
if(root->right)
st.push(root->right);
root = root->left;
}else if(!st.empty()){
root = st.top();
res.push_back(root->val);
st.pop();
if(root->right)
st.push(root->right);
root = root->left;
}
}
return res;
}
vector<int> midOrder(TreeNode* root){
vector<int> res;
//用栈
TreeNode* rc = root;
stack<TreeNode*> st;
while(rc || !st.empty()){
while(rc){
st.push(rc);
rc = rc->left;
}
rc = st.top();
res.push_back(rc->val);
st.pop();
rc = rc->right;
}
return res;
}
vector<int> postOrder(TreeNode* root){
//用栈
vector<int> res;
stack<TreeNode *> st;
TreeNode* pre = nullptr;
TreeNode* rc = root;
while(rc || !st.empty()){
while(rc){
st.push(rc);
rc = rc->left;
}
rc = st.top();
if(nullptr == rc->right || pre == rc->right){
st.pop();
res.push_back(rc->val);
pre = rc;
rc = nullptr;
}else{
rc = rc->right;
}
}
return res;
}
};
Morris遍历
//二叉树morris遍历 (线索二叉树)
void morris(TreeNode *head) {
if (nullptr == head) return;
TreeNode* cur = head;
TreeNode* mostRight = nullptr;
while (nullptr != cur) {
mostRight = cur->left;
if (nullptr != mostRight) {
while (nullptr != mostRight->right && mostRight->right != cur) {
mostRight = mostRight->right;
}
if (nullptr == mostRight->right) {
mostRight->right = cur;
cur = cur->left;
continue;
}
else {
mostRight->right = nullptr;
}
}
cur = cur->left;
}
}
其他
二分
再转动过的有序数组中寻找目标值
class Solution {
public:
/**
*
* @param A int整型一维数组
* @param n int A数组长度
* @param target int整型
* @return int整型
*/
int search(int* A, int n, int target) {
// write code here
if(n < 1) return -1;
int l=0,r=n-1;
while(l<=r){
int mid = l+((r-l+1)>>1);
if(A[mid] == target) return mid;
else if(A[mid] > target){ //变小
if(A[l] < A[r] || A[mid] < A[l] || A[l]< target){ //在一个区间
r = mid-1;
}else{
l = mid+1;
}
}else{ //变大
if(A[l] < A[r] || A[mid] > A[r] || A[r]>=target){ //在一个区间
l = mid+1;
}else{
r = mid-1;
}
}
}
return -1;
}
};
回溯
有重复项数字的全排列
class Solution {
public:
vector<vector<int> > permuteUnique(vector<int> &num) {
vector<vector<int>> res;
int n = num.size();
getAns(res,num,0);
return res;
}
void getAns(vector<vector<int>>& res,vector<int> &num,int curPos){
if(curPos >= num.size()){
res.emplace_back(num);
return;
}
set<int> isV;
int curV = num[curPos];
for(int i=curPos;i<num.size();++i){
if(isV.find(num[i]) != isV.end()) continue; //已经交换过就不能再交换了
isV.emplace(num[i]);
swap(num[curPos],num[i]);
getAns(res,num,curPos+1);
swap(num[curPos],num[i]);
}
}
};
洗牌算法
有一个数组,每次随机从剩下的元素中取值,直到数组为空,获得一个随机序列。 时间复杂度O(N),空间复杂度O(1)
//洗牌算法
void shuffle(vector<int> &arr) {
int curC = arr.size();
int del = curC-1;
while (curC > 0) {
int i = rand() % curC;
cout << arr[i] << endl;
swap(arr[i],arr[del]);
--del;
--curC;
}
}
大数据题目的解题技巧
- 哈希函数可以把数据按照种类均匀分流。
- 布隆过滤器用于集合的建立与查询,可以节省大量空间。
- 一致性哈希解决数据服务器的负载管理问题。
- 利用并查集结构做岛问题的并行计算。
- 位图解决某一范围上数字的出现情况,并可以节省大量空间。
- 利用分段统计思想,进一步节省大量空间。
- 利用堆外排序来做多个处理单元的结果合并。