前言
本文是題主準備面試時記錄下的筆記整理而來,稍顯粗陋,還請各位擼友勿噴哈!
Topic
-
目標
- 熟練使用常用數據結構的基本操作
- 加深對常用算法與技巧的理解
- 面試
-
參考
- 《程序員面試金典》
- 《劍指offer》
- Leetcode
- 《結構之法 --July》
字符串篇
1_1.judge_char_unique_in_str
1.問題描述:
- 判斷字符串中字符是否唯一
- 不使用額外數據結構(自定義數據結構)
2.解決策略
-
策略一:
- 根據字符的ASCII值進行排序
- 相鄰索引比較
-
策略二:
- 定義bool類型數組,初始化置0
- 遍歷字符串的每一字符
- 在數組相應位置,置1
- 如果出現對1置1的情況,返回false
-
策略三:
- 思路同二,換成位操作
- bool數組換成int bit[8]
- int ==> 32位
- 8 * 32 = 256
- str[i] / 32獲取數組下標
- str[i] % 32獲取偏移量
3.coding遇到的問題
- 相關頭文件
- memset() ==> <cstring> / <string.h>
- a.原型:memset(void *s int ch, size_t n)
- b.例: memset(bit, 0, sizeof(bit))
- calloc() ==> <cstdlib>
- a.例:
(bool *)calloc(256, sizeof(bool));
- a.例:
- malloc() == <cstdlib>
- memset() ==> <cstring> / <string.h>
- 三整數a,b,c排序:
- judge a > b, y==>swap()
- judge a > c, y==>swap()
- judge b > c, y==>swap()
- 判斷字符串是否為空的方法:
- s.empty()
- s == ""
- s.length() / s.size() == 0
- 動態數組初始化:
- g++編譯器會自動初始化為0或NULL
- 其他變一起可能不會,需memset()
4.代碼示例:
/*************************************************************************
> File Name: Solution.h
> Description:
(1)問題描述:
A.判斷字符串中字符是否唯一
B.不使用額外數據結構(自定義數據結構)
> Conclusion:
(1)策略一:
A.根據字符的ASCII值進行排序
B.相鄰索引比較
(2)策略二:
A.定義bool類型數組,初始化置0
B.遍歷字符串的每一字符
C.在數組相應位置,置1
D.如果出現對1置1的情況,返回false
(3)策略三:
A.思路同二,換成位操作
B.bool數組換成int bit[8]
a.int ==> 32位
b.8 * 32 = 256
C.str[i] / 32獲取數組下標
D.str[i] % 32獲取偏移量
(4)相關頭文件
A.memset() ==> <cstring> / <string.h>
a.原型:memset(void *s int ch, size_t n)
b.例: memset(bit, 0, sizeof(bit))
B.calloc() ==> <cstdlib>
a.例:
(bool *)calloc(256, sizeof(bool));
C.malloc() == <cstdlib>
(5) 三整數a,b,c排序:
A.judge a > b, y==>swap()
B.judge a > c, y==>swap()
C.judge b > c, y==>swap()
(6)判斷字符串是否為空的方法:
A.s.empty()
B.s == ""
C.s.length() / s.size() == 0
(7)動態數組初始化:
A.g++編譯器會自動初始化為0或NULL
B.其他變一起可能不會,需memset()
> Author: rh_Jameson
> Created Time: 2014年12月09日 星期二 10時49分53秒
************************************************************************/
#ifndef _SOLUTION_H
#define _SOLUTION_H
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include<cstring> //memset
#include<cstdlib> //calloc/malloc
using namespace std;
class Solution {
public:
//================Bool數組位操作版===============//
bool Is_unique_str(string &s){
if(s.empty()){ //判空
return true;
}
int bit[8]; //8個整形變量,共256位
memset(bit, 0, sizeof(bit));
for(string::iterator i = s.begin(); i < s.end(); ++i){
int index = (int) *i / 32; //獲取相應數組下標
int shift = (int) *i % 32; //獲取相應偏移位數
if(bit[index] & 1 << shift){
return false;
}
bit[index] |= 1<< shift;
}
return true;
}
//================Bool數組STL形式版===============//
bool Is_unique_strSTL(string &s){
if(s.empty())
{
return true;
}
//memset置0
//bool flag[256];
//memset(flag,0,sizeof(flag));
//calloc置0
//bool* flag = (bool *)calloc(256, sizeof(bool));
//new,自動初始化置0,但有些編譯器不自動初始化
bool* flag = new bool[256];
//bool* flag = new bool[256]();
for(string::iterator i = s.begin(); i < s.end(); ++i){
int tmp = (int) *i;
if(flag[tmp] == 0){
flag[tmp] = 1;
}
else{
return false;
}
}
delete[] flag;
return true;
}
//=====================Bool數組原始版=========================//
bool Is_unique_strOrigin(string &s){
if(s.empty())
{
return true;
}
bool flag[256];
memset(flag,0,sizeof(flag));
int len = s.size();
for(int i = 0; i < len; ++i){
int tmp = (int)s[i];
if(flag[tmp] == 0){
flag[tmp] = 1;
}
else{
return false;
}
}
return true;
}
//================字符排序版(nlogn)==================//
bool Is_unique_str_bySort(string &s){
if(s.empty()){
return true;
}
sort(&s[0],&s[0] + s.size());
int index = 0;
int len = s.size();
for(int i = 1; i < len; ++i){
if(s[index] == s[i]){
return false;
}
index++;
}
return true;
}
};
#endif
1_2.reverse_str
1.問題描述:
- 翻轉一個NULL結尾的字符串
- "abcd" => "dcba"
2.解決策略
- 策略一:首尾索引交換
- 遍歷字符獲得尾下標
- 首尾兩兩交換
- 策略二:單索引法
- strlen()獲取長度 再模2,賦給mid
- 遍歷[0,mid)
- swap(i,n - i - 1)
3.coding遇到的問題
-
交換變量的方法:
- 求和交換
- 抑或交換
- 簡潔美觀,無需臨時變量
- 編譯效率無提升
- swap同一引用變量時,有bug
- swap(a, a) => a變為0
- 臨時變量交換
-
空字符串處理:
- *str == "" or str == NULL or !str都不行
- 因為str本身有值,是一個內存地址
- 改為:str[0] == '\\0' / NULL 或 !str[0]
-
結束函數:
- return;
- exit();
- 某些平臺下,return無法結束
4.代碼示例:
/*************************************************************************
> File Name: Solution.h
> Description:
(1)問題描述:
A.翻轉一個NULL結尾的字符串
B."abcd" => "dcba"
> Conclusion:
(1)策略一:首尾索引交換
A.遍歷字符獲得尾下標
B.首尾兩兩交換
(2)策略二:單索引法
A.strlen()獲取長度 再模2,賦給mid
B.遍歷[0,mid)
C.swap(i,n - i - 1)
(3)交換變量的方法:
A.求和交換
B.抑或交換
a.簡潔美觀,無需臨時變量
b.編譯效率無提升
c.swap同一引用變量時,有bug
d.swap(a, a) => a變為0
C.臨時變量交換
(4)空字符串處理:
A. *str == "" or str == NULL or !str都不行
B. 因為str本身有值,是一個內存地址
C. 改為:str[0] == '\0' / NULL 或 !str[0]
(5)結束函數:
A.return;
B.exit();
C.某些平臺下,return無法結束
> Author: rh_Jameson
> Created Time: 2014年12月09日 星期二 17時00分06秒
************************************************************************/
#ifndef _SOLUTION_H
#define _SOLUTION_H
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
class Solution {
public:
void reverseBy2Index(char* str); //g++下傳入只能是char[],而不能是char*
void reverse(char* str);
//通過抑或交換
void swapByXor(char &a, char &b);
//通過求和交換
void swapBySum(char &a, char &b);
//通過臨時變量交換
void swapByTmp(char &a, char &b);
};
/*
* 省去臨時變量,簡潔美觀,但效率木有提升
* swap(a,a)交換同一引用變量會出現bug
* 交換完,a變為0
*/
void Solution::swapByXor(char &a, char &b){
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
void Solution::swapBySum(char &a, char &b){
a = a + b;
b = a - b;
a = a - b;
}
void Solution::swapByTmp(char &a ,char &b){
char tmp = a;
a = b;
b = tmp;
}
//===========================一個指針版本=============================//
void Solution::reverse(char* str){
//空字符串處理
if(!str[0]){
cout << "空字符串!" << endl;
return;
}
int len = strlen(str);
int mid = len / 2;
for(int i = 0; i < mid; ++i){
swapBySum(str[i],str[len - i - 1]); //i 與 len - i - 1對應
}
cout << str << endl;
}
//============================首尾指針交換版=========================//
void Solution::reverseBy2Index(char* str){
/*
*空字符數組判空:
*str == "" or str == NULL or !str都不行
*因為str本身有值,是一個內存地址
*改為:str[0] == '\0' / NULL 或 !str[0]
*/
//空字符串處理
if(!str[0]){
cout << "空字符串!" << endl;
return;
}
int last = 0;
//遍歷獲取尾元素下標
while(str[last] != '\0'){
++last;
}
--last; //移去null結尾的字符
int first = 0;
int tmp;
//反轉
while(first < last){
//swapByXor(str[first++], str[last--]);
swapBySum(str[first++], str[last--]);
//swapByTmp(str[first++], str[last--]);
}
cout << str << endl;
}
#endif
1_3.IsAnagrams
1.問題描述:
- 判斷兩個字符串是否是變位詞
- 變位詞定義:
- 單詞字符,出現次數相同
- 位置不同
- "abcd" & "bcda" => true
2.coding遇到的問題
- STL sort()
- sort(begin,end)
- C++強制轉換方法:
- static_cast<int>(obj);
- C++的string與char*的不同:
- string不能用指針訪問
- *(str + i),該訪問方式報錯
- 只能如此訪問str[i]
- char*兩種方式都行:
- str[i] & *(str + i)
- string不能用指針訪問
3.解決策略
-
策略一(Wrong):Bool數組
- 遍歷strFrom每個字符
- 在Bool數組相應位置置1
- 遍歷strTo每個字符
- 判斷每個字符在bool數組中是否置1
- 不是,返回false
- 錯誤原因:為考慮重復元素,
- 如:baad & abbd => false
-
策略二:int數組
- 思路同一
- 一起遍歷strFrom,strTo
- 每個字符,strFrom操作 + 1,strTp - 1
- 遍歷int數組,如果為0,就返回true
- 最后一輪遍歷費時間,如果是Unicode的話
-
策略三:排序
- strFrom跟strTo分別排序
- 再來一輪遍歷,比較兩者是否一樣
-
策略四:int數組2
- 遍歷strFrom
- strFrom每個字符,在int數組相應位置 + 1
- 遍歷strTo
- strTo每個字符,在int數組相應位置 - 1
- 1后,判斷值是否小于0,小于則返回false
4.代碼示例:
/*************************************************************************
> File Name: Solution.h
> Description:
(1)問題描述:
A.判斷兩個字符串是否是變位詞
B.變位詞定義:
a,單詞字符,出現次數相同
b.位置不同
C."abcd" & "bcda" => true
> Conclusion:
(1)策略一(Wrong):Bool數組
A.遍歷strFrom每個字符
B.在Bool數組相應位置置1
C.遍歷strTo每個字符
D.判斷每個字符在bool數組中是否置1
E.不是,返回false
F.錯誤原因:為考慮重復元素,
G.如:baad & abbd => false
(2)策略二:int數組
A.思路同一
B.一起遍歷strFrom,strTo
C.每個字符,strFrom操作 + 1,strTp - 1
D.遍歷int數組,如果為0,就返回true
E.最后一輪遍歷費時間,如果是Unicode的話
(3)策略三:排序
A.strFrom跟strTo分別排序
B.再來一輪遍歷,比較兩者是否一樣
(4)策略三:int數組2
A.遍歷strFrom
B.strFrom每個字符,在int數組相應位置 + 1
C.遍歷strTo
D.strTo每個字符,在int數組相應位置 - 1
E.- 1后,判斷值是否小于0,小于則返回false
(5)STL sort()
A.sort(begin,end)
(6)C++強制轉換方法:
A.static_cast<int>(obj);
(7)C++的string與char*的不同:
A.string不能用指針訪問
a.*(str + i),該訪問方式報錯
b.只能如此訪問str[i]
B.char*兩種方式都行:
a.str[i] & *(str + i)
> Author: rh_Jameson
> Created Time: 2014年12月10日 星期三 14時16分09秒
************************************************************************/
#ifndef _SOLUTION_H
#define _SOLUTION_H
#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
using namespace std;
class Solution {
public:
bool IsAnagramsOrigin(string strFrom,string strTo);
bool IsAnagrams(string strFrom,string strTo);
bool IsAnagramsByIntArray(string strFrom,string strTo);
bool IsAnagramsBySort(string strFrom,string strTo);
};
//=============int數組優化版:Correct,空間開銷適度=================//
bool Solution::IsAnagrams(string strFrom, string strTo){
if(strFrom.size() != strTo.size()){
return false;
}
int *flag = new int[256]();
//有些編譯器對動態數組不會自動初始化,需手動置0
memset(flag, 0, sizeof(*flag));
int len = strFrom.size();
int index;
for(int i = 0; i < len; ++i){
index = static_cast<int>(strFrom[i]); //改c++強制轉換
*(flag + index) += 1;
}
for(int i = 0; i< len; ++i){
index = static_cast<int>(strTo[i]);
*(flag + index) -= 1;
if(*(flag + index) < 0 ){
return false;
}
}
return true;
}
//===================排序版:時間nlogn,無需額外空間===================//
bool Solution::IsAnagramsBySort(string strFrom,string strTo){
if(strFrom.size() != strTo.size()){
return false;
}
sort( &strFrom[0], &strFrom[0] + strFrom.size() );
sort( &strTo[0], &strTo[0] + strTo.size() );
if(strFrom == strTo){
return true;
}
else{
return false;
}
}
//==================int數組版:Correct,空間開銷大=====================//
bool Solution::IsAnagramsByIntArray(string strFrom, string strTo){
if(strFrom.size() != strTo.size()){
return false;
}
int *flag = new int[256]();
//有些編譯器對動態數組不會自動初始化,需手動置0
memset(flag, 0, sizeof(*flag));
int len = strFrom.size();
int index,index2;
for(int i = 0; i < len; ++i){
index = static_cast<int>(strFrom[i]); //改c++強制轉換
index2 = static_cast<int>(strTo[i]);
*(flag + index) += 1;
*(flag + index2) -= 1;
}
for(int i = 0; i< 256; ++i){
if(*(flag + i) != 0 ){ //數組全為0,則兩者是變位詞
return false;
}
}
return true;
}
//===================bool數組原始版:忽略重復元素,Wrong!==================//
bool Solution::IsAnagramsOrigin(string strFrom, string strTo){
if(strFrom.size() != strTo.size()){
return false;
}
bool *flag = new bool[256]();
//有些編譯器對動態數組不會自動初始化,需手動置0
memset(flag, 0, sizeof(*flag));
int len = strFrom.size();
int index;
for(int i = 0; i < len; ++i){
//int index = (int) ( *(strFrom + i) ); //與char*不同,string中無法通過*(str + i)來訪問
index = (int) strFrom[i]; //改c++強制轉換
*(flag + index) = true;
}
for(int i = 0; i< len; ++i){
index = (int) strTo[i];
if(*(flag + index) != true){
return false;
}
}
return true;
}
#endif
1_4.str_replace_space
1.問題描述:
- 將字符串中的所有空格替換為%20
- 前提:首尾空格去除
- 不用額外空間
2.策略一:空格替換 & 移位
- 去除首尾空格 & 判空
- 遍歷空格數目
- 重置字符串的大小,以及首尾iterator
- 遍歷移位 & 替換
3.策略二:使用STL的replace方法
- 去除首尾空格 & 判空
- 遍歷替換replace(pos, num, obj)
4.消除首尾空格關鍵代碼:
- s.erase(0, s.find_first_not_of(' '))
- s.erase(s.find_last_not_of(' ') + 1, s.size() - 1);
- 不能寫成erase(s.begin(),s.find_first_not_of(' '))
- find_first_not_of()返回類型為:size_t,而非iterator
- find_last_not_of同樣遵循C,D
5.resize()原型:
- s.resize(size, "c")
- 例:s = "abc"; s.resiz(5,"d") ==> s = "abcdd"
6.代碼示例:
/**********************************************************************************
> File Name: Solution.h
> Description:
(1)問題描述:
A.將字符串中的所有空格替換為%20
B.前提:首尾空格去除
C.不用額外空間
> Conclusion:
(1)策略一:空格替換 & 移位
A.去除首尾空格 & 判空
B.遍歷空格數目
C.重置字符串的大小,以及首尾iterator
D.遍歷移位 & 替換
(2)策略二:使用STL的replace方法
A.去除首尾空格 & 判空
B.遍歷替換replace(pos, num, obj)
(3)消除首尾空格關鍵代碼:
A. s.erase(0, s.find_first_not_of(' '))
B. s.erase(s.find_last_not_of(' ') + 1, s.size() - 1);
C.不能寫成erase(s.begin(),s.find_first_not_of(' '))
D.find_first_not_of()返回類型為:size_t,而非iterator
E.find_last_not_of同樣遵循C,D
(4)resize()原型:
A.s.resize(size, "c")
B.例:s = "abc"; s.resiz(5,"d") ==> s = "abcdd"
> Author: rh_Jameson
> Created Time: 2014年12月11日 星期四 09時26分22秒
**********************************************************************************/
#ifndef _SOLUTION_H
#define _SOLUTION_H
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
class Solution {
public:
//=====================使用stl中的相關方法========================//
string replace_space(string s){
if(s[0] == ' '){
s.erase(0, s.find_first_not_of(' '));
}
if(s[s.size() - 1] == ' '){
s.erase(s.find_last_not_of(' ') + 1, s.size() - 1);
}
int len = s.size();
for(int i = 1; i < len; ++i){
if(s[i] == ' '){
s.replace(i,1,"%20");
}
}
return s;
}
//========================空格替換 & 移位========================//
string replace_spaceOrigin(string s){
string::iterator first_iter = s.begin();
string::iterator last_iter = s.end() - 1;
//消除首尾空格
if(*first_iter == ' '){
//不能寫成erase(s.begin(),s.find_first_not_of(' '))
s.erase(0, s.find_first_not_of(' ')); //改' '
}
if(*last_iter == ' '){
s.erase(s.find_last_not_of(' ') + 1, s.size() - 1);
}
//先消除首尾空格,再判空
if(s.empty()){
cout << "空串或無實際意義的串" << endl;
return s;
}
//遍歷獲得空格數目
int blank_cnt = 0;
for(string::iterator i = s.begin(); i < s.end(); ++i){
if(*i == ' '){
blank_cnt++;
}
}
//計算移動幾位
int mov_cnt = blank_cnt * 2;
//重置s的大小
s.resize(s.size() + mov_cnt,'='); //resize(size_value, fill_char)
last_iter = s.end() - mov_cnt - 1; //s中最后一個有意義的字符
first_iter = s.begin();
//s[s.size() + mov_cnt] = '\0';
//遍歷移位
for(string::iterator i = last_iter; i >= first_iter; --i){
if(*i == ' '){ //替換空格
*(i + mov_cnt) = '0';
*(i + mov_cnt - 1) = '2';
*(i + mov_cnt - 2) = '%';
mov_cnt -= 2;
}
else{
*(i + mov_cnt) = *i; //移位賦值
}
}
return s;
}
};
#endif
1_5.str_compression
1.問題描述:
- 字符串壓縮
- 將重復出現的字符轉成數字形式
- "aabcccccaaa" ==> "a2b1c5a3"
2.策略一:原字符串操作法
- 不用額外空間
- 去除空格
- 判空
- 字符壓縮
- 快慢索引指向值相等,cnt++,快索引向前移位
- 不等,則判斷cnt是否等于1
- cnt == 1
- 慢索引向前移動一步
- 將快索引的值賦給慢索引的值
- 在慢索引處insert "1"
- 快索引向前移動一位
- cnt != 1
- 將cnt轉成字符串并替換到慢索引的下一位置
- cnt置1
- 最后一組重復字符的處理
3.策略二:另開一字符串
- 去處空格 & 判空
- 字符壓縮
- 快慢索引指向值相等,cnt++,快索引向前移位
- 不等,新字符串插入慢索引指向字符和cnt值
- 慢索引指向快索引指向值,cnt置1
- 最后一組重復字符的處理,同B,但僅作一次
4.itoa相關:
定義: 整型數值轉為字符串
例: int n = 10;==》"10"
-
itoa函數
- 所屬頭文件<cstdlib>
- 原型:itoa(int_value,string_buf,base)
- base:進制,可選2,8,10,16
- linux下不可用
-
linux下如何使用itoa
- 自己寫一個
- 用stringstream
- stringstream ss << int_value
- ss >> str
- c++ 11提供:string s = std::to_string(int_value);
5.字符串連接函數append():
- strComp.append(s, idx, 1);
- strComp.append(s);
- 參見cplusplus.com
6.代碼示例:
/********************************************************************************
> File Name: Solution.h
> Description:
(1)問題描述:
A.字符串壓縮
B.將重復出現的字符轉成數字形式
C."aabcccccaaa" ==> "a2b1c5a3"
> Conclusion:
(1)策略一:原字符串操作法
A.不用額外空間
B.去除空格
C.判空
D.字符壓縮
a.快慢索引指向值相等,cnt++,快索引向前移位
b.不等,則判斷cnt是否等于1
c.cnt == 1
*.慢索引向前移動一步
*.將快索引的值賦給慢索引的值
*.在慢索引處insert "1"
*.快索引向前移動一位
d.cnt != 1
*.將cnt轉成字符串并替換到慢索引的下一位置
*.cnt置1
E.最后一組重復字符的處理
(2)策略二:另開一字符串
A.去處空格 & 判空
B.字符壓縮
a.快慢索引指向值相等,cnt++,快索引向前移位
b.不等,新字符串插入慢索引指向字符和cnt值
c.慢索引指向快索引指向值,cnt置1
C.最后一組重復字符的處理,同B,但僅作一次
(3)itoa相關:
A.定義: 整型數值轉為字符串
B.例: int n = 10;==》"10"
C.itoa函數
a.所屬頭文件<cstdlib>
b.原型:itoa(int_value,string_buf,base)
*.base:進制,可選2,8,10,16
c.linux下不可用
D.linux下如何使用itoa
a.自己寫一個
b.用stringstream
*.stringstream ss << int_value
*.ss >> str
c.c++ 11提供:
string s = std::to_string(int_value);
d.
(4)字符串連接函數append():
A.strComp.append(s, idx, 1);
B.strComp.append(s);
C.參見cplusplus.com
> Author: rh_Jameson
> Created Time: 2014年12月11日 星期四 15時10分23秒
***********************************************************************************/
#ifndef _SOLUTION_H
#define _SOLUTION_H
#include<iostream>
#include<string>
#include<algorithm>
#include<sstream>
#include<cstdlib>
using namespace std;
class Solution {
public:
//int轉string
string itoa(int n){
stringstream ss;
ss << n;
string tmp;
ss >> tmp;
/*linux下沒有itoa函數
string tmp;
itoa(cnt, tmp, 10);
*/
//c++11才可以用
//string tmp = std::to_string(cnt);
return tmp;
}
//消除空格
void removeStrSpace(string &s){
string::iterator iter = s.begin();
string::iterator end = s.end();
while(iter < end){
if(*iter == ' '){
s.erase(iter);
}
else{
++iter;
}
}
}
//=======================不用額外字符串版本=====================//
//字符串壓縮
string strCompressionBetter(string s){
//消除空格
removeStrSpace(s);
//判空
if(s.empty()){
cout << "空字符串" << endl;
}
//字符壓縮
int cnt = 1, idx = 0, i;
string tmp;
for(i = 1; i < s.size(); ++i){
if(s[idx] == s[i]){
cnt++;
}
else{
if(cnt != 1){
tmp = itoa(cnt);
s.replace(++idx,1,tmp);
s[++idx] = s[i];
cnt = 1;
}
else{
s[++idx] = s[i];
s.insert(idx++,"1");
i++;
}
}
}
//最后的判斷 & 處理
if(cnt == 1){
s[++idx] = s[i];
s.insert(idx++,"1");
}
if(cnt != 1){
tmp =itoa(cnt);
s.replace(++idx,1,tmp);
s[++idx] = s[i];
}
s.resize(idx);
return s;
}
//======================另開字符串版本====================//
//字符串壓縮
string strCompression(string s){
//消除空格
removeStrSpace(s);
//判空
if(s.empty()){
cout << "空字符串" << endl;
}
//字符壓縮
string strComp,tmp;
int idx = 0, i, cnt = 1, len = s.size();
/*快慢下標,相等,cnt++
* 不等,將s[idx]和cnt插入strComp中
*/
for(i = 1; i < s.size(); ++i){
if(s[idx] == s[i]){
cnt++;
}
else{
strComp.append(s, idx, 1);
tmp = itoa(cnt);
strComp.append(tmp);
//idx += cnt;
idx = i;
cnt = 1;
}
}
//最后重復一次處理
strComp.append(s, idx, 1);
tmp = itoa(cnt);
strComp.append(tmp);
return strComp;
}
};
#endif
1_6.matrix_rotate
1.問題描述
- N * N矩陣表示圖像
- 每像素4字節
- 實現圖像旋轉90度
- 不用額外空間
2.策略一:四點輪換法
- 遍歷行數N/2
- 將行中每個結點旋轉到相應位置
- 通過tmp變量進行輪換
- 時間復雜度O(N^2)
3.策略二:對角線替換
- 交換對角線兩邊元素
- 對每一列元素進行逆置
- 逆時針旋轉繞橫軸
- 順時針旋轉繞縱軸
4.生成隨機數
- srand((int)time(NULL));
- r = rand() % 10
5.傳遞二維數組參數
- int a[10][10]
- int a[][10]
- 不可以用二級指針
- int** a;
- 相關網址:
http://www.wutianqi.com/?p=1822
6.代碼示例:
/*************************************************************************
> File Name: Solution.h
> Description:
(1)問題描述
A.N * N矩陣表示圖像
B.每像素4字節
C.實現圖像旋轉90度
D.不用額外空間
> Conclusion:
(1)策略一:四點輪換法
A.遍歷行數N/2
B.將行中每個結點旋轉到相應位置
C.通過tmp變量進行輪換
D.時間復雜度O(N^2)
(2)策略二:對角線替換
A.交換對角線兩邊元素
B.對每一列元素進行逆置
a.逆時針旋轉繞橫軸
b.順時針旋轉繞縱軸
(3)生成隨機數
A.srand((int)time(NULL));
B.r = rand() % 10
(4)傳遞二維數組參數
A.int a[10][10]
B.int a[][10]
C.不可以用二級指針
a.int** a;
b.相關網址:
http://www.wutianqi.com/?p=1822
> Author: rh_Jameson
> Created Time: 2014年12月14日 星期日 12時17分44秒
************************************************************************/
#ifndef _SOLUTION_H
#define _SOLUTION_H
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
class Solution {
public:
void printMatrix(const int n,int a[][7]){
for(int i = 0; i < n; ++i){
for(int j = 0; j < n; ++j){
cout << a[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
//=======================矩陣旋轉:四點輪換法,Accepted=======================//
//逆時針旋轉90度
void matrix_rotate_reverse(const int n, int a[][7]){
if(n == 0){
cout << "空矩陣" << endl;
}
int col = n, len = n;
int midline = n / 2, tmp;
for(int i = 0; i < midline; ++i){
for(int j = i; j < col - 1 - i; ++j){
tmp = a[j][i];
a[j][i] = a[i][len - 1 - j];
a[i][len -1 -j] = a[len - 1 - j][len - 1 - i];
a[len - 1 - j][len - 1 - i] = a[len - 1 - i][j];
a[len - 1 - i][j] = tmp;
}
}
printMatrix(n, a);
}
//順時針旋轉90度
void matrix_rotateByExchg(const int n, int a[][7]){
if(n == 0){
cout << "空矩陣" << endl;
}
int col = n, len = n;
int midline = n / 2, tmp;
for(int i = 0; i < midline; ++i){
for(int j = i; j < col - 1 - i; ++j){
tmp = a[i][j];
a[i][j] = a[len - 1 - j][i];
a[len - 1- j][i] = a[len - 1 - i][len - 1 - j];
a[len - 1 - i][len - 1 - j] = a[j][len - 1 - i];
a[j][len - 1 - i] = tmp;
}
}
printMatrix(n, a);
}
//=====================矩陣旋轉:對角線替換,Accepted======================//
void swap(int &a, int &b){
int tmp;
tmp = a;
a = b;
b = tmp;
}
void matrix_rotate(const int n, int a[][7]){
int len = n;
//對角線兩側元素互換
for(int i = 0; i < len; ++i){
for(int j = i; j < len; ++j){
swap(a[i][j],a[j][i]);
}
}
//根據縱軸逆置元素
for(int line = 0; line < len; ++line){
for(int first = 0,last = len - 1; first < last; ++first, --last){
swap(a[line][first],a[line][last]);
}
}
printMatrix(n, a);
}
};
#endif
1_7.matrix_clear_zero
1.問題描述:
- M * N矩陣
- 若某個元素為0,所在行與列均清零
2.解決策略
策略一:哈希表保存清零的行與列
- 遍歷矩陣
- 用map記錄元素為0的行, 列
- 對相應行清零
- 相應列清零
策略二:復用0行0列記錄要清零的行,列
- 不用額外空間,直接復用0行0列的空間
- 判斷0行跟0列是否存在0,bool標志真/假
- 遍歷其余行跟列
- 元素為0的行列,存到0行0列的相應位置
- 遍歷清零
- 檢測bool標志,判斷0行0列是否存在0
- 存在,則對0行 / 0列清零
3.Coding遇到的問題
- vector<vector<int> > m:
- 相當于二維數組 m[i][j]
- 行數:m.size()
- 列數:m[0].size()
- m[i][j]形式,通過2個for循環可生成隨機矩陣
- vector形式不能生成
- 相關鏈接
- map & hashtable:
- C++ STL嚴格來說沒有實現哈希表結構
- map底層是紅黑樹,訪問復雜度為logN
- 哈希表一般是常數時間訪問
- 性能:unordered_map > hash_map > map
- 需要有序關聯容器的話要用map
- 相關鏈接
- STL---hash_map
- c++ hash_map 詳細介紹
- map / hash_map / unordered_map 性能測試
- C++ STL中哈希表 hash_map介紹
4.代碼示例:
/*************************************************************************
> File Name: Solution.h
> Description:
(1)問題描述:
A.M * N矩陣
B.若某個元素為0,所在行與列均清零
> Conclusion:
(1)策略一:哈希表保存清零的行與列
A.遍歷矩陣
B.用map記錄元素為0的行, 列
C.對相應行清零
D.相應列清零
(2)策略二:復用0行0列記錄要清零的行,列
A.不用額外空間,直接復用0行0列的空間
B.判斷0行跟0列是否存在0,bool標志真/假
C.遍歷其余行跟列
D.元素為0的行列,存到0行0列的相應位置
E.遍歷清零
F.檢測bool標志,判斷0行0列是否存在0
G.存在,則對0行 / 0列清零
(3)vector<vector<int> > m:
A.相當于二維數組 m[i][j]
B.行數:m.size()
C.列數:m[0].size()
D.m[i][j]形式,通過2個for循環可生成隨機矩陣
E.vector形式不能生成
F.http://blog.csdn.net/qingdujun/article/details/17499871
(4)map & hashtable:
A.C++ STL嚴格來說沒有實現哈希表結構
B.map底層是紅黑樹,訪問復雜度為logN
C.哈希表一般是常數時間訪問
D.性能:unordered_map > hash_map > map
E.需要有序關聯容器的話要用map
F.http://blog.chinaunix.net/uid-20384806-id-3055333.html
G.http://yiluohuanghun.blog.51cto.com/3407300/1086355
H.http://blog.csdn.net/peter_teng/article/details/8433395
I.http://www.cnblogs.com/waytofall/archive/2012/06/04/2534386.html
> Author: rh_Jameson
> Created Time: 2014年12月14日 星期日 22時24分29秒
************************************************************************/
#ifndef _SOLUTION_H
#define _SOLUTION_H
#include<iostream>
#include<string>
#include<algorithm>
#include<map>
//#include<hash_map>
using namespace std;
class Solution {
public:
void printMatrix(int matrix[1][2]){
int col_num = 2;
int line_num = 1;
for(int i = 0; i < line_num; ++i){
for(int j = 0; j < col_num; ++j){
cout << matrix[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
//=====================map保存要清0的行與列:Accepted=====================//‘
void setZeroesByHash(int matrix[5][4]) {
int col_num = 4;
int line_num = 5;
map<int, int> col_map, line_map; //記錄清零的行與列
int col_zero = 0, line_zero = 0; //清零行,列的個數
//遍歷記錄清零的行與列
for(int i = 0; i < line_num; ++i){
for(int j = 0; j < col_num; ++j){
if(matrix[i][j] == 0){
line_map[++line_zero] = i;
col_map[++col_zero] = j;
}
}
}
int tmp;
//所在行清零
while(line_zero > 0){
tmp = line_map[line_zero];
for(int i = 0; i < col_num; ++i){
matrix[tmp][i] = 0;
}
--line_zero;
}
printMatrix(matrix);
//所在列清零
while(col_zero > 0){
tmp = col_map[col_zero];
for(int i = 0; i < line_num; ++i){
matrix[i][tmp] = 0;
}
--col_zero;
}
printMatrix(matrix);
}
//=====================不用額外空間實現:Accepted=====================//
void setZeroes(int matrix[1][2]) {
int col_num = 2;
int line_num = 1;
bool flag_line = false,flag_col = false;
//判斷第零行是否有0
for(int i = 0; i < col_num; ++i){
if(matrix[0][i] == 0){
flag_line = true;
break;
}
}
//判斷第零列是否有0
for(int i = 0; i < line_num; ++i){
if(matrix[i][0] == 0){
flag_col = true;
break;
}
}
//將出現0的行,列記錄到第0行和第零列上
for(int i = 1; i < line_num; ++i){
for(int j = 1; j < col_num; ++j){
if(matrix[i][j] == 0){
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
//清零
for(int i = 1; i < line_num; ++i){
for(int j = 1; j < col_num; ++j){
if(matrix[i][0] == 0 || matrix[0][j] == 0){
matrix[i][j] = 0;
}
}
}
//判斷第零行,第零列是否要清零
if(flag_line){
for(int i = 0; i < col_num; ++i){
matrix[0][i] = 0;
}
}
if(flag_col){
for(int i = 0; i < line_num; ++i){
matrix[i][0] = 0;
}
}
printMatrix(matrix);
}
};
#endif
1_8.Reverse Words In A String
1.問題描述
- 給一字符串s
- 將字符串s中的單詞反轉
- 不使用額外空間
2.例子
- "the sky is blue" ==> "blue is sky the"
3.解決方案
- 策略一:反轉法
- 思路:
- 每個單詞都反轉一次
- 反轉整個字符串
- 步驟:
- 消除頭部空格
- 消除尾部空格
- 消除word間重復的空格
- 反轉每個單詞,最后反轉整個字符串
- 思路:
- 優化策略:
- 思路:同一
- 步驟:
- 消除重復元素
- 判斷首尾有無空格,有則刪之
- 反轉每個單詞,最后反轉整個字符串
4.Coding遇到的問題
-
C++獲取字符串長度:
- 兩種方式:str.length() / str.size()
- 使用C版本的string頭文件,則調用strlen()
- 返回字符串實際長度,即不包括結束符
-
C++去除首尾空格:
- C++中沒有相關的trim()方法
- 使用stl的相關函數實現
- 使用<ctype.h>(<cctype>)中的isspace遍歷實現
- isspace() example
-
sizeof(string)與sizeof(int)不同
- int分配在棧,string分配空間在堆
- string的地址存在棧中
- sizeof(string)是string地址的大小
- sizeof(string)不同編譯器/系統,大小不同
- 64位linux,g++:8
- 32位win,vc6.0:16
-
傳遞指針字符串(void fun(string* s))
- 傳遞的實際是字符串地址的地址
- 建議改為引用,即string& s
-
string.erase()使用
- erase(pos): 刪除pos處的一個字符
- erase(pos,n): 刪除pos處開始的n個字符
- erase(first,last) 刪除first到last之間的字符
- first,last,pos為迭代器
5.代碼示例:
/*************************************************************************
> File Name: Solution for Reverse Words in a String
> Description:
(1)問題描述:
A.給一字符串
B.將字符串中的單詞逆轉
C."the sky is blue" ==> "blue is sky the"
D.不使用額外空間
> Conclusion:
(1)策略一:反轉法
A.思路:
a.每個單詞都反轉一次
b.反轉整個字符串
B.消除頭部空格
C.消除尾部空格
D.消除word間重復的空格
E.反轉每個單詞,最后反轉整個字符串
(1.5)優化策略:
A.思路:同一
B.消除重復元素
C.判斷首尾有無空格,有則刪之
D.反轉每個單詞,最后反轉整個字符串
(2)C++獲取字符串長度:
A.兩種方式:str.length()/str.size()
B.使用C版本的string頭文件,則調用strlen()
C.返回字符串實際長度,即不包括結束符
(3)C++去除首尾空格:
A.C++中沒有相關的trim()方法
B.使用stl的相關函數實現
C.使用<ctype.h>(<cctype>)中的isspace遍歷實現
(4)sizeof(string)與sizeof(int)不同
A.int分配在棧,string分配空間在堆
B.string的地址存在棧中
C.sizeof(string)是string地址的大小
D.sizeof(string)不同編譯器/系統,大小不同
a.64位linux,g++:8
b.32位win,vc6.0:16
(6)傳遞指針字符串(void fun(string* s))
A.傳遞的實際是字符串地址的地址
B.建議改為引用,即string& s
(7)string.erase()使用
A.erase(pos): 刪除pos處的一個字符
B.erase(pos,n): 刪除pos處開始的n個字符
C.erase(first,last) 刪除first到last之間的字符
D.first,last,pos為迭代器
> Author: rh_Jameson
> Created Time: 2014年12月07日 星期日 17時10分20秒
************************************************************************/
#include<string>
#include<cctype>
#include <algorithm>
#include <functional>
#include <locale>
using namespace std;
class Solution {
public:
//反轉函數
void reverse(int p, int q, string& s){
char tmp;
while(p < q){
tmp = s[p];
s[p++] = s[q];
s[q--] = tmp;
}
}
//======================反轉法原始版:Accepted,44ms======================//
void reverseWordsOrigin(string &s) {
int p = 0, q = p;
//去除首部空格
while(s[0] == ' '){
if(s == ""){
break;
}
s.erase(s.begin());
}
//去除尾部空格
while(s[s.size() - 1] == ' '){
if(s == ""){
break;
}
s.erase(s.end() - 1);
}
//去除單詞間重復空格
while(p < s.size()){
if(s[p] == ' ' && s[p] == s[p + 1]){
s.erase(s.begin() + p);
continue;
}
p++;
}
p = 0;
int len = s.size();
//逐個單詞反轉
while(q < len){
if(s[q] != ' '){
if(q == len - 1){
reverse(p, q, s);
}
q++;
}
else{
reverse(p, q - 1, s);
p = ++q;
}
}
//對整個字符串進行反轉
reverse(0, len - 1, s);
}
//======================反轉法首尾消除優化版:Accepted,44ms======================//
// trim from start
inline string <rim(string &s) {
s.erase(s.begin(), find_if(s.begin(), s.end(), not1(ptr_fun<int, int>(isspace))));
return s;
}
// trim from end
inline string &rtrim(string &s) {
s.erase(find_if(s.rbegin(), s.rend(), not1(ptr_fun<int, int>(isspace))).base(), s.end());
return s;
}
// trim from both ends
inline string &trim(string &s) {
return ltrim(rtrim(s));
}
//main
void reverseWordsOpt(string &s) {
int p = 0, q = p;
//去除首尾空格
trim(s);
//去除單詞間重復空格
while(p < s.size()){
if(s[p] == ' ' && s[p] == s[p + 1]){
s.erase(s.begin() + p);
continue;
}
p++;
}
p = 0; //重置索引p
int len = s.size();
//逐個單詞反轉
while(q < len){
if(s[q] != ' '){
if(q == len - 1){
reverse(p, q, s);
}
q++;
}
else{
reverse(p, q - 1, s);
p = ++q;
}
}
//對整個字符串進行反轉
reverse(0, len - 1, s);
}
//======================反轉法重復消除優化版:Accepted,44ms======================//
void reverseWords(string &s) {
int p = 0, q = p;
//去除單詞間重復空格
while(p < s.size()){
if(s == "" ){
break;
}
if(s[p] == ' ' && s[p] == s[p + 1]){
s.erase(s.begin() + p);
continue;
}
p++;
}
if(s[0] == ' '){
s.erase(s.begin());
}
if(s[s.size() - 1] == ' '){
s.erase(s.end() - 1);
}
p = 0; //重置p
int len = s.size();
//逐個單詞反轉
while(q < len){
if(s == ""){
break;
}
if(s[q] != ' '){
if(q == len - 1){
reverse(p, q, s);
}
q++;
}
else{
reverse(p, q - 1, s);
p = ++q;
}
}
//對整個字符串進行反轉
reverse(0, len - 1, s);
}
};