劍指offer十題刷(三)
1、找一個只出現一次的數,其餘的數都出現兩次
給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
說明:
你的演算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?
示例 1:
輸入: [2,2,1]
輸出: 1
示例 2:
輸入: [4,1,2,1,2]
輸出: 4
class Solution {
public:
int singleNumber(vector<int>& nums) {
size_t i=0;
int num=0;
for (i=0;i<nums.size();i++)
{
num^=nums[i];
}
return num;
}
};
2、字元排列組合
給定一個僅包含數字 2-9 的字串,返回所有它能表示的字母組合。
給出數字到字母的對映如下(與電話按鍵相同)。注意 1 不對應任何字母。
示例:
輸入:“23”
輸出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
說明:
儘管上面的答案是按字典序排列的,但是你可以任意選擇答案輸出的順序。
// 建立數字對映的字串陣列
string letterMap[10] = { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
class Solution {
public:
// 核心思想:總計深度為digits.size()層的遞迴,
// 每層遞迴在字串中一個字元進行組合。
void combineStr(const string& digits, size_t index, const string& str, vector<string>&
strs)
{
if (index == digits.size())
{
strs.push_back(str);
return;
}
// 獲取數字對應的字元陣列
string letters = letterMap[digits[index] - '0'];
for (size_t i = 0; i < letters.size(); ++i)
{
combineStr(digits, index + 1, str + letters[i], strs);
}
}
vector<string> letterCombinations(string digits) {
vector<string> strs;
if (digits.empty())
return strs;
size_t index = 0;
string str;
// 遞迴子問題組合字串
combineStr(digits, index, str, strs);
return strs;
}
};
3、楊輝三角
給定一個非負整數 numRows,生成楊輝三角的前 numRows 行。
在楊輝三角中,每個數是它左上方和右上方的數的和。
示例:
輸入: 5
輸出:
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> vv;//vv可以看做是vector中的每個元素也是vector
vv.resize(numRows);//設定二維陣列的行數
//逐行遍歷,開闢空間
for(size_t v=0;v<numRows;++v)
{
vv[v].resize(v+1,0);//第0行有0+1個數據
//第一列和最後一列都是1
vv[v][0]=1;
vv[v][v]=1;
}
for(size_t v=0;v<vv.size();++v)//行
{
for(size_t i=0;i<vv[v].size();++i)//列
{
if(vv[v][i]==0)
vv[v][i]=vv[v-1][i-1]+vv[v-1][i];
}
}
return vv;
}
};
4、字串(僅考慮字母和數字字元)是否是迴文,忽略字母大小寫。
給定一個字串,驗證它是否是迴文串,只考慮字母和數字字元,可以忽略字母的大小寫。
說明:本題中,我們將空字串定義為有效的迴文串。
示例 1:
輸入: “A man, a plan, a canal: Panama”
輸出: true
示例 2:
輸入: “race a car”
輸出: false
思路一 :原(0——9)的ascll碼值%32與原(A——Z)的ascll碼值%32有重合部分。而原字元-‘A’之後,(0——9)的ascll碼值都變成了負數,且不影響字母%32的結果。
class Solution {
public:
bool isPalindrome(string s) {
if (s.empty())
return true;
int begin = 0;
int end = s.size() - 1;
while (begin < end)
{
// 從前往後找一個數字字元或者字母
while (begin != end)
{
if (IsNumberOrLetter(s[begin]))
break;
++begin;
}
// 從後往前找一個數字字元或者字母
while (begin < end)
{
if (IsNumberOrLetter(s[end]))
break;
--end;
}
if (begin < end)
{
// 檢測start和end位置字元是否相等 或者是否不區分大小的相等
if ((s[begin] + 32 - 'a') % 32 != (s[end] + 32 - 'a') % 32)
return false;
++begin;
--end;
}
}
return true;
}
bool IsNumberOrLetter(char c)
{
if (c >= '0' && c <= '9' ||
c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z')
{
return true;
}
return false;
}
};
思路二 :那麼題設忽略大小寫,為了區分大寫字母和數字字元,可以將大寫字母全部轉換成小寫,更加方便地比較判斷。
class Solution {
public:
bool NumOrStr(char c)//判斷一個字元是不是字母或者數字字元,如果是就要滿足迴文條件
{
if((c>='0'&&c<='9')||(c>='a'&&c<='z'))
return true;
return false;
}
bool isPalindrome(string s) {
if(s.empty())return true;
//因為提示忽略大小寫,將大寫字母統一改成小寫,方便比較
size_t begin=0,end=s.size()-1;
while(begin<=end){
if(s[begin]>='A'&&s[begin]<='Z')
s[begin]+=32;
++begin;
}
begin=0;
while(begin<end)
{
//從前向後尋找第一個滿足條件的字元
while(begin<end)
{
if(NumOrStr(s[begin]))
break;
begin++;
}
//從後向前尋找第一個滿足條件的字元
while(begin<end)
{
if(NumOrStr(s[end]))
break;
end--;
}
if(begin<end)//如果begin==end,如“a.”直接跳過,return true
{
//到這個位置s[begin]和s[end]都是字母或者數字字元,只需驗證,二者是否相同
if(s[begin]!=s[end])
return false;
begin++,end--;
}
}
return true;
}
}
5、給定兩個字串形式的非負整數 num1 和num2 ,計算它們的和。
注意:
num1 和num2 的長度都小於 5100.
num1 和num2 都只包含數字 0-9.
num1 和num2 都不包含任何前導零。
你不能使用任何內建 BigInteger 庫, 也不能直接將輸入的字串轉換為整數形式。
class Solution {
public:
string addStrings(string num1, string num2) {
size_t l1=num1.size();
size_t l2=num2.size();
//以長字串作為外迴圈
if(l1<l2){
num1.swap(num2);
swap(l1,l2);
}
int cret=0;
int cstep=0;
string str;
str.reserve(l1+1);//保證空間足夠
for(size_t i=0;i<l1;i++)
{
cret=num1[l1-i-1]-'0'+cstep;
cstep=0;
if(i<l2)
cret+=num2[l2-i-1]-'0';
if(cret>9){
cstep=1;
cret-=10;
}
str+=cret+'0';
}
if(cstep)//需要判斷,最後一位是否有進位
str+='1';
reverse(str.begin(),str.end());//因為高位的值反而被放在了後面,所以要逆置
return str;
}
};
6、逆置前2k個字元的前k個字元
給定一個字串和一個整數 k,你需要對從字串開頭算起的每個 2k 個字元的前k個字元進行反轉。如果剩餘少於 k 個字元,則將剩餘的所有全部反轉。如果有小於 2k 但大於或等於 k 個字元,則反轉前 k 個字元,並將剩餘的字元保持原樣。
示例:
輸入: s = “abcdefg”, k = 2
輸出: “bacdfeg”
要求:
該字串只包含小寫的英文字母。
給定字串的長度和 k 在[1, 10000]範圍內。
string reverseStr(string s, int k) {
for(int i = 0; i < s.length(); i += 2 * k){
reverse(s.begin() + i, min(s.begin() + i + k, s.end()));
}
return s;
}
string reverseStr(string s, int k) {
for(int start = 0; start < s.size(); start += 2 * k){
int i = start, j = min(start + k - 1, (int)s.size() -1);
for(; i < j; i++, j--)
swap(s[i],s[j]);
}
return s;
}
7、有序二維陣列查詢一個數
在一個二維陣列中(每個一維陣列的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int l=array[0].size()-1;
int h=0;
while(h<array.size()&&l>=0)
{
if(target>array[h][l])
h++;
else if(target<array[h][l])
l--;
else
return true;
}
return false;
}
};
8、逆序輸出連結串列中的val
輸入一個連結串列,按連結串列值從尾到頭的順序返回一個ArrayList。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> ArrayList;
ListNode*cur=head;
while(cur)
{
ArrayList.push_back(cur->val);
cur=cur->next;
}
vector<int> result;
for(int i=ArrayList.size()-1;i>=0;i--)
result.push_back(ArrayList[i]);
return result;
}
};