刷题日记:面试经典 150 题 DAY5

刷题日记:面试经典 150 题 DAY4

  • [125. 验证回文串](#125. 验证回文串)
  • [28. 找出字符串中第一个匹配项的下标](#28. 找出字符串中第一个匹配项的下标)
  • [151. 反转字符串中的单词](#151. 反转字符串中的单词)
  • [6. Z 字形变换](#6. Z 字形变换)
  • [68. 文本左右对齐](#68. 文本左右对齐)

125. 验证回文串

原题链接 125. 验证回文串

双指针,一前一后,遇到非数字字母跳过即可

cpp 复制代码
class Solution {
public:
    bool isPalindrome(string s) {
        int i = 0, j = s.size()-1;
        while(i < j) {
            while(i<j && !isalnum(s[i])) i++;
            while(i<j && !isalnum(s[j])) j--;
            if(tolower(s[i]) != tolower(s[j])) {
                return false;
            }
            i++, j--;
        }
        return true;
    }
};

28. 找出字符串中第一个匹配项的下标

原题链接 28. 找出字符串中第一个匹配项的下标

子串匹配问题,有很多算法,其中最著名的是KMP算法,时间复杂度是 O ( M + N ) O(M+N) O(M+N)。之前短暂的理解过,现在又不明白了。贴一个讲解 可能是全网最清晰的KMP算法讲解

理解不了就硬背

cpp 复制代码
class Solution {
public:
    int strStr(string haystack, string needle) {
        int len_n = needle.size();
        int next[len_n];
        next[0] = -1;
        for(int i = 1, j = -1;i < len_n;i++){
            while(j > -1 && needle[i] != needle[j+1]) j = next[j];
            if(needle[i] == needle[j+1]) j++;
            next[i] = j;
        }

        for(int i = 0, j = -1;i < haystack.size();i++) {
            while(j > -1 && haystack[i] != needle[j+1]) j = next[j];
            if(haystack[i] == needle[j+1]) j++;
            if(j == len_n-1) {
                return i-len_n+1;
            }
        }
        return -1;
    }
};

找到一个好理解的Sunday算法

算法仍然包括两步:预处理和移动模式串

基本流程是:

  • 左对齐,开始进行匹配
  • 一旦匹配失败,对"下一位"进行检查
  • 找到模式串中该字母最后出现的位置,然后对齐,开启下一轮匹配
    为了加速这个过程,我们预处理出一个键值对,键即字母表中的各个字母,对应的值是该字母在模式串中出现的位置(事实上,我们使用一个数组进行模拟;并且处理值,使得其意味着"此时模式串应该向后平移几位")
cpp 复制代码
class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size(), m = needle.size();
        if(m > n) return -1;
        vector<int> shifts(26,m+1);
        for(int i = 0;i < m;i++) {
            shifts[needle[i]-'a'] = m-i;
        }

        int s = 0, i;
        while(s <= n-m) {
            i = 0;
            while(haystack[s+i] == needle[i]) {
                i++;
                if(i == m) {
                    return s;
                }
            }
            if(s+m >= n) break;
            s += shifts[haystack[s+m]-'a'];
        }
        return -1;
    }
};

151. 反转字符串中的单词

原题链接 151. 反转字符串中的单词

  • 第一步,去掉前后的空格
  • 第二步,双指针,均从串末尾开始遍历,一个指向单词的开头,一个指向单词的结尾
    • 交替地判断正在被遍历的是字母还是空格
cpp 复制代码
class Solution {
public:
    string reverseWords(string s) {
        int i,j;
        int len = s.size();
        for(i = 0;i < len && s[i] == ' ';i++);
        for(j = len-1;j >= 0 && s[j] == ' ';j--);
        s = s.substr(i,j-i+1);
        
        i = s.size()-1;
        j = s.size()-1;
        string result = "";
        while(i >= 0) {
            while(i >= 0 && s[i] != ' ') i--;
            result += s.substr(i+1,j-i) + " ";
            while(i >= 0 && s[i] == ' ') i--; 
            j = i;
        }
        result = result.substr(0,result.size()-1);
        return result;
    }
};

6. Z 字形变换

原题链接 6. Z 字形变换

直接分类讨论,设我们讨论在Z字形中的第i行第j个字母,其在原串中的位置是index

  • 每一行的index都从i开始
  • 对于第一行和最后一行,j每增加1,index增加2*(numRows-1)
  • 对于中间
    • j是偶数,则index增加2*(numRows-i-1)
    • j是奇数,则index增加2*i
cpp 复制代码
class Solution {
public:
    string convert(string s, int numRows) {
        int len = s.size();
        if(numRows == 1 ||  len <= numRows) return s;

        string result;
        int t = 2*(numRows-1);
        for(int i = 0;i < numRows;i++) {
            int j = 0;
            int index = i;
            while(index < len) {
                result.push_back(s[index]);
                if(i == 0 || i == numRows-1) {
                    index += t;
                } else if(j%2 == 0) {
                    index += t-2*i;
                } else {
                    index += 2*i;
                }
                j++;
            }
        }
        return result;
    }
};

68. 文本左右对齐

原题链接 68. 文本左右对齐

做的我有点脑溢血了,大致分三步

  • 第一步,将原单词列分成连续的区间,每个区间中的单词应该以左右对齐放在一行中
    • 设单词数量是 n n n,单词总长度是 s u m sum sum,则满足 s u m + n − 1 ≤ m a x W i d t h sum+n-1 \leq maxWidth sum+n−1≤maxWidth的尽可能长的一组单词应该放到一行(即,最少在每个单词之间放一个空格)
      • 这一步我脑残突然发了,死活写不出来。其实简化一下问题就是:有一个数组,一个最大和maxSum。写一个函数,将数组分成几个尽可能长的连续片段,使得在每个连续片段内,数组元素的和都小于等于maxSum。代码应该是:

        cpp 复制代码
        vector<vector<int>> splitArray(const vector<int>& nums, int maxSum) {
        	vector<vector<int>> result;
        
        	int currentSum = 0;
        	vector<int> currentSegment;
        
        	for (int num : nums) {
        		if (currentSum + num > maxSum) {
        			// 当前片段的和超过maxSum,将当前片段加入结果,并开始新的片段
        			result.push_back(currentSegment);
        			currentSegment.clear();
        			currentSum = 0;
        		}
        		currentSegment.push_back(num);
        		currentSum += num;
        	}
        	// 将最后一个片段加入结果
        	result.push_back(currentSegment);
        	return result;
        }
        • 应该是 执行循环判断是否下标越界-->再循环内先判断是否已经超出最大和-->构造序列
  • 第二步,对每组单词,执行左右对齐。假设需要 s s s个空格放到 n n n个间隔之中去,思路是先给每个间隔分配 ⌊ s n ⌋ \lfloor \frac{s}{n} \rfloor ⌊ns⌋个空格,再给前 s m o d    n s \mod n smodn个间隔多分配上一个空格
  • 第三步,给剩下的单词分配左对齐。这个好说。
cpp 复制代码
class Solution {
public:
    struct Line {
        int st;
        int ed;
        int lw;
    };
    string space_factory(int n) {
        return string(n,' ');
    }

    vector<string> fullJustify(vector<string>& words, int maxWidth) {
        int len = words.size();
        int wordsize[len];
        for(int i = 0;i < len;i++) {
            wordsize[i] = words[i].size();
        }

        vector<Line> lines;
        int start = 0, count = 0, sum = 0;
        while(start < len) {
            count = 0;
            sum = 0;
            while(start+count < len) {
                if(sum+count+wordsize[start+count]>maxWidth) {
                    lines.push_back({start,start+count-1,sum});
                    break;
                }
                sum += wordsize[start+count];
                count++;
            }
            start += count;
        }
        start -= count;

        vector<string> res;
        for(int i = 0;i < lines.size();i++) {
            auto line = lines[i];
            int sum_spaces = maxWidth-line.lw;
            string new_line = "";

            new_line += words[line.st];
            if(line.st == line.ed) {
                new_line += space_factory(sum_spaces);
            } else {
                int sigle_spaces = (sum_spaces)/(line.ed-line.st);
                int remain_spaces = (sum_spaces)%(line.ed-line.st);
                for(int j = 1;line.st+j<=line.ed;j++) {
                    if(j-1 < remain_spaces) {
                        new_line += space_factory(sigle_spaces+1);
                    } else {
                        new_line += space_factory(sigle_spaces);
                    }
                    new_line += words[line.st+j];
                }
            }
            res.push_back(new_line);
        }

        string new_line = "";
        new_line += words[start];
        sum = wordsize[start];
        for(int i = start+1;i < len;i++) {
            new_line += " ";
            new_line += words[i];
            sum +=  wordsize[i];
        }
        new_line += space_factory(maxWidth-sum-(len-start-1));
        res.push_back(new_line);

        return res;
    }
};
相关推荐
掘金安东尼9 分钟前
Amazon Lambda + API Gateway 实战,无服务器架构入门
算法·架构
码流之上1 小时前
【一看就会一写就废 指间算法】设计电子表格 —— 哈希表、字符串处理
javascript·算法
快手技术3 小时前
快手提出端到端生成式搜索框架 OneSearch,让搜索“一步到位”!
算法
CoovallyAIHub1 天前
中科大DSAI Lab团队多篇论文入选ICCV 2025,推动三维视觉与泛化感知技术突破
深度学习·算法·计算机视觉
NAGNIP1 天前
Serverless 架构下的大模型框架落地实践
算法·架构
moonlifesudo1 天前
半开区间和开区间的两个二分模版
算法
moonlifesudo1 天前
300:最长递增子序列
算法
CoovallyAIHub1 天前
港大&字节重磅发布DanceGRPO:突破视觉生成RLHF瓶颈,多项任务性能提升超180%!
深度学习·算法·计算机视觉
CoovallyAIHub1 天前
英伟达ViPE重磅发布!解决3D感知难题,SLAM+深度学习完美融合(附带数据集下载地址)
深度学习·算法·计算机视觉
聚客AI2 天前
🙋‍♀️Transformer训练与推理全流程:从输入处理到输出生成
人工智能·算法·llm