字符串編程題題目解析(From leetcode)——1

原題目的地址:https://leetcode.com/tag/string/

1.
Give a string s, count the number of non-empty (contiguous) substrings that have the same number of 0’s and 1’s, and all the 0’s and all the 1’s in these substrings are grouped consecutively.
Substrings that occur multiple times are counted the number of times they occur.
Example 1:
Input: “00110011”
Output: 6
Explanation: There are 6 substrings that have equal number of consecutive 1’s and 0’s: “0011”, “01”, “1100”, “10”, “0011”, and “01”.

Notice that some of these substrings repeat and are counted the number of times they occur.

Also, “00110011” is not a valid substring because all the 0’s (and 1’s) are not grouped together.

Example 2:
Input: “10101”
Output: 4
Explanation: There are 4 substrings: “10”, “01”, “10”, “01” that have equal number of consecutive 1’s and 0’s.

Note:
s.length will be between 1 and 50,000.
s will only consist of “0” or “1” characters.

思路:
1.根據題意 字符串僅由‘0’‘1’組成 。
2.符合條件的字串必定是前半部分全‘1’後半部分全‘0’,或前半部分全‘0’後半部分全‘1’。
這裏寫圖片描述

class Solution {
public:
    int countBinarySubstrings(string s)
    {
        vector<int> _v;
        int count = 1;
        int ret = 0;
        for (size_t i = 1; i <= s.size(); ++i){//注意這裏是反常的 i <= s.size() 
            if (s[i] == s[i - 1]){             //這是因爲要用‘\0’和最後一個字符比較得出!=的
                count++;                       //結論
            }
            else{
            return ret;
    }   _v.push_back(count);           //從而跳轉到註釋這一行求出把最後有幾個相同的字符
                count = 1;                     //插入vector中
            }
        }
        for (size_t i = 1; i < _v.size(); ++i){
            ret += min(_v[i], _v[i - 1]);
        }

};

2.
Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it. If no such solution, return -1.
For example, with A = “abcd” and B = “cdabcdab”.
Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; and B is not a substring of A repeated two times (“abcdabcd”).
Note:
The length of A and B will be between 1 and 10000.

思路:
首先根據題必須要瞭解到 如果重複A串可以使B成爲A的字串的話 A串數量不可能大於B.length() / A.length() + 2(見註釋)
每一次加長後 A串個數count++ 在加長後的串其中找B 找到了返回count。

class Solution
{
public:
    int repeatedStringMatch(const string& A, const string& B) {
        string AR = A;//做這種題儘量不要更改參數字符串
        while (1){
            static int count = 1;
            if (count > B.length() / A.length() + 2)//爲什麼加2?
                //abcdabcdabcd 3個A  //cdabcda 1個B    B.length()/A.length() =  1
                //最少需要3個abcd
                //+2解決B字符串中前後各有半段A字符串的情況。
                return -1;
            if (AR.find(B) != string::npos)//find()找不到時返回的是string::nops
                return count;
            else{
                AR += A;
            }
            ++count;
        }
    }
};

3.
Given a time represented in the format “HH:MM”, form the next closest time by reusing the current digits. There is no limit on how many times a digit can be reused.
You may assume the given input string is always valid. For example, “01:34”, “12:09” are all valid. “1:34”, “12:9” are all invalid.
Example 1:
Input: “19:34”
Output: “19:39”
Explanation: The next closest time choosing from digits 1, 9, 3, 4, is 19:39, which occurs 5 minutes later. It is not 19:33, because this occurs 23 hours and 59 minutes later.

Example 2:
Input: “23:59”
Output: “22:22”
Explanation: The next closest time choosing from digits 2, 3, 5, 9, is 22:22. It may be assumed that the returned time is next day’s time since it is smaller than the input time numerically.

思路:
1.由於需要尋找據當前時間最近合法時間 所以從當前時間之後隨着時間的自然流動方向找合法的數。
2.由於最早得到的時間格式爲 時:分 形式不利於計算所以想將其轉化爲以秒爲單位 , 待找到合適的以秒爲單位的時間後再將其轉化爲 時:分形式
3.沒過一秒的新時間用來判斷是否合法 (方法說明見註釋)
4.解決本題必須熟練掌握庫函數的使用 和STL的使用

string NextCloseTime(const string& time)
{
    int mins[] = { 600, 60, 10, 1 };//爲秒單位時間轉爲時:分形式保存每一位進制
    string newtime = time;
    unsigned int colon = newtime.find(':');
    string next = "0000";//表示找到的下一個時間的string
    //算現在時間用秒錶示是多少
    int cur = stoi(newtime.substr(0, colon)) * 60 + stoi(newtime.substr(colon + 1));
    for (size_t i = 1, d = 0; i < 1440 && d < 4; ++i){//一天是1440秒 合法的時間必在1440秒之內會出現
        int m = (cur + i) % 1440;
        for (d = 0; d < 4; ++d){
            next[d] = '0'+ m / mins[d];
            m %= mins[d];
            if (newtime.find(next[d]) == string::npos)
                break;//新時間裏沒有原數字不合法
            //這兩層循環是核心 d 和 i 的巧妙運用 即如果內循環是因爲d==4而推出的話
            //next string中存放的時間符合要求 外循環也d==4而推出。
        }
    }
    return next.substr(0, 2) + ':' + next.substr(2, 2);//格式轉化
}

4.
Given a non-empty string s, you may delete at most ‘deletecount ’character. Judge whether you can make it a palindrome.
Example 1:
Input: “aba”
Output: True

Example 2:
Input: “abca”
Output: True
Explanation: You could delete the character ‘c’.

Note:
The string will only contain lowercase characters a-z. The maximum length of the string is 50000.

思路:
試想如果允許刪除的字符個數是無限個 則一定可以形成Palindromic string 所以本題跟蹤deletecount很關鍵。
從兩頭便利字符串 遇到不相同的一對 一邊跳過 另一邊不動 繼續比 前提是deletecount > 0 遇到要刪除的 deletecount– – 。遞歸查找。

bool valid(string ret, int begin, int end, int deletecount)
{//deletecount 表示允許被刪掉的個數。
    if (begin >= end) return true;
    else if (ret[begin] == ret[end])
        return valid(ret, begin + 1, end - 1, deletecount);
    else
        return deletecount > 0 &&( valid(ret, begin + 1, end, deletecount - 1)\
        || valid(ret, begin, end - 1, deletecount - 1));
}

bool validPalindrome(const string& s)
{
    string ret = s;
    return valid(ret, 0, s.length() - 1, 1);
}

5.
Given a string containing only three types of characters: ‘(‘, ‘)’ and ‘*’, write a function to check whether this string is valid. We define the validity of a string by these rules:
Any left parenthesis ‘(’ must have a corresponding right parenthesis ‘)’.
Any right parenthesis ‘)’ must have a corresponding left parenthesis ‘(‘.
Left parenthesis ‘(’ must go before the corresponding right parenthesis ‘)’.
‘*’ could be treated as a single right parenthesis ‘)’ or a single left parenthesis ‘(’ or an empty string.
An empty string is also valid.

Example 1:
Input: “()”
Output: True

Example 2:
Input: “(*)”
Output: True

Example 3:
Input: “(*))”
Output: True

思路:
本題代碼實現不難 但是想起來難 大多數人一開始會考慮用stack來解決問題這樣複雜化了問題。
本題應以‘極端假設法’考慮 題幹中規定’*’可以是’(’ 也可以是 ‘)’
那我們就假設所有的 ‘’ 都是’(’ 和所有的’‘都是 ‘)’ 定義StarIsleft 和 StarIsright兩個變量記錄這兩種境況下的 ‘)’‘(’個數。
如圖:
這裏寫圖片描述

bool Is_corresponding(const string& corresponding)
{
    string test = corresponding;
    int StarIsleft = 0;  //假設所有*都是(
    int StarIsright = 0;//假設所有*都是  )
    for (size_t i = 0; i < test.length(); ++i){
        if (test[i] == '('){
            StarIsleft++;
            StarIsright++;
        }
        else if (test[i] == ')'){
            StarIsleft--;
            StarIsright--;
        }
        else{
            StarIsleft++;
            StarIsright--;
        }
        StarIsright = max(StarIsright, 0// )+ *數量大於( StarIsright小於0 沒有關係  //因爲規則中*是可以調整的根據規則 4. 5.
        if (StarIsleft < 0)//這一句在循環體內 如果在遍歷字符串過程中( + * 的數量少於 )
                            //根據規則3. 則一定會有)得不到匹配 所以直接返回false
                            //從左到右遍歷過程中任意時刻 ( + * 必須 大於等於 )
            return false;
    }
    return StarIsright == 0;
}

6.
Initially, there is a Robot at position (0, 0). Given a sequence of its moves, judge if this robot makes a circle, which means it moves back to the original place.
The move sequence is represented by a string. And each move is represent by a character. The valid robot moves are R (Right), L (Left), U (Up) and D (down). The output should be true or false representing whether the robot makes a circle.
Example 1:
Input: “UD”
Output: true

Example 2:
Input: “LL”
Output: false
//本題簡單 不予描述思路

bool judgeCircle(string moves) 
{
    string test = moves;
    int coordi1 = 0;
    int coordi2 = 0;
    for (size_t i = 0; i < test.length(); ++i){
        if (test[i] != 'U' && test[i] != 'D' && test[i] != 'L'\
            && test[i] != 'R')
        ++i;
        else if (test[i] == 'U') coordi1 -= 1;
        else if (test[i] == 'D') coordi1 += 1;
        else if (test[i] == 'L') coordi2 -= 1;
        else coordi2 += 1;
    }
    return coordi1 == 0 && coordi2 == 0;

}

7.
Given a string, your task is to count how many palindromic substrings in this string.
The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.
Example 1:
Input: “abc”
Output: 3
Explanation: Three palindromic strings: “a”, “b”, “c”.

Example 2:
Input: “aaa”
Output: 6
Explanation: Six palindromic strings: “a”, “a”, “a”, “aa”, “aa”, “aaa”.

Note:
The input string length won’t exceed 1000

思路:
本題與第五題不同的是本題要求的是‘how many palindromic substrings in this string’. 而不是把string變成一個palindromic string 。
且 different substrings even they consist of same characters.

如此一來不可以通過從兩邊向中間的找發了  要從中間向兩邊找
從中間找有要注意兩種情況
1.  palindromic string 是:‘abccba’;
2. palindromic string 是:‘abcdcba’;

int countSubstrings(string s) {
    int ret = 0; int n = s.length();
    for (int i = 0; i < n; ++i){
        for (int j = 0; i - j >= 0 && i + j < n && s[i - j] == s[i + j]; j++)
            ret++;//查找“abcecba”這樣奇數個字符的Palindromic字符串個數
        for (int j = 0; i - 1 - j >= 0 && i + j < n && s[i - 1 - j] == s[i + j]; j++)
            ret++;//查找“abccba”這樣偶數個字符的Palindromic字符的個數
    }
    return ret;
}

8.
You need to construct a string consists of parenthesis and integers from a binary tree with the preorder traversing way.
The null node needs to be represented by empty parenthesis pair “()”. And you need to omit all the empty parenthesis pairs that don’t affect the one-to-one mapping relationship between the string and the original binary tree.
Example 1:
Input: Binary tree: [1,2,3,4]
1
/ \
2 3
/
4

Output: “1(2(4))(3)”

Explanation: Originallay it needs to be “1(2(4)())(3()())”,
but you need to omit all the unnecessary empty parenthesis pairs.
And it will be “1(2(4))(3)”.

Example 2:
Input: Binary tree: [1,2,3,null,4]
1
/ \
2 3
\
4

Output: “1(2()(4))(3)”

Explanation: Almost the same as the first example,
except we can’t omit the first parenthesis pair to break the one-to-one mapping relationship between the input and the output.

遞歸和?  :  的組合運用可以使問題變得簡單。


    string tree2str(TreeNode* t) {
        return !t ? "" : to_string(t->val) + (t->left ? "(" + tree2str(t->left) + ")" : t->right ? "()" : "")
            + (t->right ? "(" + tree2str(t->right) + ")" : "");

9.
Write a function to check whether an input string is a valid IPv4 address or IPv6 address or neither.
IPv4 addresses are canonically represented in dot-decimal notation, which consists of four decimal numbers, each ranging from 0 to 255, separated by dots (“.”), e.g.,172.16.254.1;
Besides, leading zeros in the IPv4 is invalid. For example, the address 172.16.254.01 is invalid.
IPv6 addresses are represented as eight groups of four hexadecimal digits, each group representing 16 bits. The groups are separated by colons (“:”). For example, the address 2001:0db8:85a3:0000:0000:8a2e:0370:7334 is a valid one. Also, we could omit some leading zeros among four hexadecimal digits and some low-case characters in the address to upper-case ones, so 2001:db8:85a3:0:0:8A2E:0370:7334 is also a valid IPv6 address(Omit leading zeros and using upper cases).
However, we don’t replace a consecutive group of zero value with a single empty group using two consecutive colons (::) to pursue simplicity. For example, 2001:0db8:85a3::8A2E:0370:7334 is an invalid IPv6 address.
Besides, extra leading zeros in the IPv6 is also invalid. For example, the address 02001:0db8:85a3:0000:0000:8a2e:0370:7334 is invalid.
Note: You may assume there is no extra space or special characters in the input string.
Example 1:
Input: “172.16.254.1”

Output: “IPv4”

Explanation: This is a valid IPv4 address, return “IPv4”.

Example 2:
Input: “2001:0db8:85a3:0:0:8A2E:0370:7334”

Output: “IPv6”

Explanation: This is a valid IPv6 address, return “IPv6”.

Example 3:
Input: “256.256.256.256”

Output: “Neither”

Explanation: This is neither a IPv4 address
nor a IPv6 address.
思路:
拿到string 先判斷他可能是IPv4 還是IPv6  再按照各自的標準分塊判斷
瞭解一下 getline() 和stringstream

bool IsValidIPv4Block(string& block)
{
    int num = 0;
    if (block.size() < 0 || block.size() > 3)
        return false;//判斷每一小塊IPv4地址長度是否合法
    for (size_t i = 0; i < block.size(); ++i){//不允許某一塊不止一位且第一位爲‘0’
        if (i == 0 && block[i] == '0' && block.size() > 1 || !isalnum(block[i]))
            return false;
        else{//將字符串轉化爲整型
            num *= 10;
            num += block[i] - '0';
        }
    }
    return num <= 255;//每一塊大小不可以大於255
}
const string vaildIPv6chars("1234567890ABCDEFabcdef");//定一個全局變量

bool IsValidIPv6Block(string& block)
{
    if (block.size() < 0 || block.size() > 4)
        return false;//判斷每一小塊IPv6地址長度是否合法
    for (size_t i = 0; i < block.size(); ++i){//每一塊的字符必須合法
        if (vaildIPv6chars.find(block[i]) == string::npos)
            return false;
    }
    return true;
}

string validIPAddress(string IP)
{
    string block;
    string rets[3] = { "IPv4", "IPv6", "Neither" };
    stringstream ss(IP);//定義一個ss流
    if (IP.substr(0, 4).find('.') != string::npos){//IPv4
        for (size_t i = 0; i < 4; ++i){
            if (!getline(ss, block, '.') || !IsValidIPv4Block(block))
                return rets[2];
        }
        return ss.eof() ? rets[0] : rets[2];
    }
    else if (IP.substr(0, 5).find(':') != string::npos){//IPv6
        for (size_t i = 0; i < 8; ++i){//如果getline()失敗或這一塊判定爲非法返回Neither
            if (!getline(ss, block, ':') || !IsValidIPv6Block(block))
                return rets[2];
        }
        return ss.eof() ? rets[1] : rets[2];//getline()函數已經成功讀到ss流結尾 返回IPv6
    }
    return false;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章