1-10

2. Add Two Numbers

思路:结合示例可以看到其实就是完成链表对应位置相加来模拟加法运算。

首先想到要返回头结点,则头结点的创建过程单独拿出来(两个都非空,则头结点一定存在)。并设置好pre=head。

在后续中模式pre->next=node,pre=node。在都不为空的情况下,每次都要检查上一次计算设置的carryFlag,以及重新设置carryFlag。

当有一个为空时,不用针对l1和12两种情况重复写代码,只需l1=l1?l1:l2即可。这时也要注意可能的进位,直到两个都为空。

两个都为空,再考察是否有进位,如果有要新建一个结点。这个其实合并了两种情况:初始长度相等和初始长度不等。

get:使用初始化列表(4种情况必须用初始化列表)。注意变量的作用域,不能仅在if..else...中完成后续使用变量的定义。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        bool carryFlag = 0;
        ListNode *head = NULL;
        if (l1->val+l2->val < 10) {
            head = new ListNode(l1->val+l2->val);
            carryFlag = 0;
        } else {
            head = new ListNode(l1->val+l2->val-10);
            carryFlag = 1;
        }
        ListNode *pre = head;
        ListNode *node = NULL;
        l1 = l1->next;
        l2 = l2->next;
        while(l1 && l2) {
            if (l1->val+l2->val+carryFlag < 10) {
                node = new ListNode(l1->val+l2->val+carryFlag);
                carryFlag = 0;
            } else {
                node = new ListNode(l1->val+l2->val+carryFlag-10);
                carryFlag = 1;
            }
            pre->next = node;
            pre = node;
            l1 = l1->next;
            l2 = l2->next;
        }
        l1 = l1?l1:l2;
        if (l1) {
            while(l1) {
                if (l1->val+carryFlag < 10) {
                    node = new ListNode(l1->val+carryFlag);
                    carryFlag = 0;
                } else {
                    node = new ListNode(l1->val+carryFlag-10);
                    carryFlag = 1;
                }
                pre->next = node;
                pre = node;
                l1 = l1->next;
            }
        }
        if (carryFlag) {
            node = new ListNode(1);
            pre->next = node;
        }
        return head;
    }
};

3. Longest Substring Without Repeating Characters

思路:该子串一定有开始位置在0-len-1,所以对子串的首字符在0-len-1之间遍历,在这个过程中不断后移临时pos,直到有重复字符出现。在这个过程中维持更新最大长度即可。在程序写好之后可以看到,如果是空串也是可以正确处理的。

这个问题可以参照kmp做一个优化,当这个过程中出现重复字符时,下一次遍历index就可以直接从该重复字符上一次出现的下一个位置开始,因为从前面的index开始的话必然会再次在该位置上看到该重复字符,不可能产生更长的不重复子串。则需要记录每个字符出现的位置,为此开一个int型的字符数大小的数组,并在每次index发生更新时进行重新赋值-1。

外层循环index从0-len-1遍历,内层循环pos从index到len-1做遍历,因为有index = arr[s[pos]]+1的更新,外层循环写成while比for更方便。

另外注意内层循环while(pos<len)跳出时有两种情况:找到重复字符,此时需要index更新开始下次大迭代;pos=len,此时不需要再继续了,这已经是可能的最大长度了。对这两种情况要判断并分别执行不同处理。

get:ascii字符的范围是0-127,所以正好可以开128的数组。(如果限定了具体字符范围,可能提前终止,比如最大可能长度就是26)

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = s.length();
        int index = 0;
        int arr[128];
        int maxCnt = 0;
        while(index < len) {
            for (int i = 0; i < 128; i++) {
                arr[i] = -1;
            }
            int cnt = 0;
            int pos = index;
            while(pos < len) {
                if (arr[s[pos]] != -1) {
                    break;
                } else {
                    arr[s[pos]] = pos;
                    cnt++;
                }
                pos++;
            }
            if (cnt > maxCnt) {
                maxCnt = cnt;
            }
            if (pos == len) {
                break;
            } else {
                index = arr[s[pos]]+1;
            }
        }
        return maxCnt;
    }
};

5. Longest Palindromic Substring

思路:求最长回文子串,想法用动态规划来解。首先要明确dp[i][j]的意义为首尾在i,j的回文串长度。状态转移方程:if(s[i] == s[j]),且中间构成回文串(这一点很重要),dp[i][j]=dp[i+1][j-1]+2;if(s[i]!=s[j]),dp[i][j]=0。另外,可以采取遍历回文子串中间字符的方法来做,复杂度同样为O(n^2)。

在写出大致转移方程后,一定要认真考虑三个方面。初始状态:dp[i][i] = 1。循环顺序:i递减,j递增;而且要满足i<j,不仅如此在s[i]=s[j]时,若i+1=j,则dp[i][j]=2,若dp[i+1][j-1]=0(即中间不构成回文串),则dp[i][j]=0。

另外,该题目要求返回最长回文子串,在长度发生更新时要记录下标。这里初始长度的设置:考虑到空串,直接返回空串;对非空串,初始长度设置为1,并记录下标为0,0。这一点很细节,如果不厘清的话容易出各种问题。

在解本题时,出现的问题主要在不自觉地混淆回文串与回文序列,导致写的方程不对。

get:c++中,string.substr(pos, n)可以用于截取子串。

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        if (!len) {
            return "";
        }
        int dp[len][len];
        for (int i = 0; i < len; i++) {
            dp[i][i] = 1;
        }
        int maxLen = 1;
        int index_i = 0;
        int index_j = 0;
        for (int i = len-2; i >= 0; i--) {
            for (int j = i+1; j < len; j++) {
                if (s[i] == s[j]) {
                    if (i+1 == j) {
                        dp[i][j] = 2;
                    } else if (!dp[i+1][j-1]){
                        dp[i][j] = 0;
                    } else {
                        dp[i][j] = dp[i+1][j-1]+2;
                    }
                } else {
                    dp[i][j] = 0;
                }
                if (dp[i][j] > maxLen) {
                    maxLen = dp[i][j];
                    index_i = i;
                    index_j = j;
                }
            }
        }
        return s.substr(index_i,index_j-index_i+1);
    }
};

6. ZigZag Conversion

思路:这道题只需要简单模拟这个Z字形排列即可,不需要去找每一行在原string中出现位置。

具体来说:定义一个numRows维的vector,对string中每个字符依次加入到对应的vector即可。

在这个过程中,用row==0,row==numRows-1来确定下次移动方向的更改。另外需要将第一个字符放入第一个vector中,并设置preRow和direction,避免与前面规则的冲突。还有一些特殊情况需要处理:string为空,行为1。

get:vector型的数组:vector<int> vecArr[numRows]。

class Solution {
public:
    string convert(string s, int numRows) {
        int len = s.length();
        if (!len) {
            return "";
        }
        if (numRows == 1)
            return s;
        vector<int> vecArr[numRows];
        vecArr[0].push_back(s[0]);
        int direction = 1;
        int preRow = 0;
        for (int i = 1; i < len; i++) {
            vecArr[preRow+direction].push_back(s[i]);
            preRow = preRow+direction;
            if (preRow == numRows-1) {
                direction = -1;
            } else if (preRow == 0) {
                direction = 1;
            }
        }
        string resultString = "";
        for (int i = 0; i < numRows; i++) {
            for (int j = 0; j < vecArr[i].size(); j++) {
                resultString += vecArr[i][j];
            }
        }
        return resultString;
    }
};

8. String to Integer(atoi)

思路:按照string中字符出现顺序自左向右做atoi过程。

首先,略过所有‘ ’,在实现时while(index<len && str[index]==' ' && index++);,这里用到了短路求值的技巧。若index == len,则return 0(不存在不是‘ ’的字符,这里连带着将空串处理了)此时str[index]必须是+,-,0-9,否则return 0。此时若str[index]==+,-,设置sign后略过,否则设置sign=1。接下来的必须为0-9,开始处理数字。这个过程中需要用long long型来记录数字,并每次检查是否超过一定范围(字符串很长,即使long long也是不够用的)。最后按照要求return即可。

get:(result >1<<32)是不对的,1是int,左移32越界;正确写法:(result > (long long)1<<32)。

class Solution {
public:
    int myAtoi(string str) {
        int len = str.length();
        int index =0;
        while(index<len && str[index]==' ' && ++index);
        if (index == len) {
            return 0;
        }
        if ((str[index]<'0' || str[index]>'9') && str[index]!='+' && str[index]!='-') {
            return 0;
        }
        int sign = 1;
        if (str[index] == '+') {
            index++;
        } else if(str[index] == '-') {
            sign = -1;
            index++;
        }
        if (str[index]<='9' && str[index]>='0') {
            while(index<len && str[index]=='0' && ++index);
            long long result = 0;
            while(index<len && str[index]<='9' && str[index]>='0') {
                result = result*10+str[index]-'0';
                if (result > (long long)1<<32) {
                    break;
                }
                index++;
            }
            int int_max = ~(1<<31);
            int int_min = 1<<31;
            result = result*sign;
            if (result < int_min) {
                result = int_min;
            } else if (result > int_max) {
                result = int_max;
            }
            return result;
        } else {
            return 0;
        }
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值