字符串编程题题目解析(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’。
字符串编程题题目解析(From leetcode)——1_第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两个变量记录这两种境况下的 ‘)’‘(’个数。
如图:
字符串编程题题目解析(From leetcode)——1_第2张图片

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;
}

你可能感兴趣的:(编程题,C++,数据结构与算法)