Cracking the Coding Interview习题总结(一)

本文解析了《Cracking the Coding Interview》一书第一章中的经典算法题目,包括字符串字符互异判断、字符串乱序同构判断、URL化、字符串压缩、矩阵旋转等算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CC150-Chapter 1 数组与字符串

刷leetcode遇到瓶颈之后,开始打算分类学习面试中的算法,于是就开始学习Cracking the Coding Interview第六版,并且配合其中的练习题,主要用Java或python实现,以下是对第一章中题目的总结。


1.1 判断字符串中字符互异

题目描述:实现一个算法,确定一个字符串中的所有字符是否全都不同。如果不允许使用额外的存储结构。

解法1:首先确定组成字符串的字符集是ASCII还是Unicode。假设由ASCII字符组成,先判断字符串长度是否大于128(字符集的长度),若大于则一定存在重复字符。然后创建布尔类型的数组char_set[128]记录出现在字符串中的字符。当扫描到某一字符时,若char_set中对应为TRUE,表示该字符已出现在字符串中,返回FALSE。
因为需要扫描一遍字符串,故时间复杂度为O(n),空间复杂度为O(1)。

解法2:不允许使用额外存储结构的情况下,从前往后扫描字符串,比较每一个字符和其后面所有的字符是否相同。时间复杂度为O(n^2)。

def checkDifferent(self, iniString):
    for i in xrange(len(iniString)):
        for j in xrange(i+1, len(iniString)):
            if iniString[i] == iniString[j]:
                return False
    return True

1.2 判断两个字符串是否乱序同构

题目描述:给定两个字符串,判断其中一个字符串的字符重新排列后,能否变成另一个字符串。

思路:首先需要注意一些细节,例如大小写是否敏感,是否需要考虑空格。根据同构的定义,只需要判断两个字符串中出现的字符及其出现次数是否一致。

解法1:用字典记录字符串中出现的字符及其出现次数,但代码运行时间较长。

def checkSam(self, stringA, stringB):
    tmp = {}
    for i in stringA:
        if not tmp or i not in tmp:
            tmp[i] = 1
        else:
            tmp[i] += 1
    for j in stringB:
        if j in tmp:
            tmp[j] -= 1
        else:
            return False #StringB中的字符在StringA中没有出现
    for d in tmp:
        if tmp[d] > 0:
            return False #两个字符串中字符出现次数不等
    return True

解法2:类似1.1中创建int类型的数组A[128]和B[128]分别记录A、B串中字符出现的次数并比较。首先通过判断字符串长度不等时不存在同构来优化。

public boolean checkSam(String stringA, String stringB) {
        if(stringA.length() != stringB.length())
            return false;
        int[] A = new int[128];
        int[] B = new int[128];
        for(int i = 0; i < stringA.length(); i++)
        {
            A[stringA.charAt(i)]++;
        }
        for(int i = 0; i < stringA.length(); i++)
        {
            B[stringB.charAt(i)]++;
        }
        for(int i = 0; i < 128; i++)
        {
            if(A[i] != B[i])
                return false;
        }
        return true;
    }

1.3 URLify(字符替换)

题目描述:将字符串中的空格全部替换为“%20”。假定该字符串有足够的空间存放新增的字符,并且知道字符串的真实长度。

解法:利用String类的replace方法很直接,但会返回一个新的String,如果要求在原有字符串中修改,则需要使用char数组。

public String replaceSpace(String iniString, int length) {
        return iniString.replace(" " , "%20");
    }

1.4 判断字符串是否可排列为回文序列

题目描述:判断一个给定的字符串是否可通过重新排列成为一个回文字符串。

思路:回文序列即从前往后和从后往前遍历是一样的。从字符出现的次数上来分析,如果至多只有一个字符出现的次数为奇数次,则该字符串可排列为回文序列,因为其余的字符可平均分配在字符串的两侧。

1.5 字符串压缩

题目描述:利用字符重复出现的次数,实现字符串压缩功能。例如字符串“aabcccccaaa”经压缩会变成“a2b1c5a3”。若压缩后的字符串没有变短,则返回原先的字符串。

解法:

public String zipString(String iniString) {
    String tmp = "";
    int count = 0;
    for(int i = 0; i < iniString.length(); i++)
    {
        if(i==0||iniString.charAt(i)!= niString.charAt(i-1))
        {
            if(count > 0)
                tmp += count;
            tmp += iniString.charAt(i);
            count = 1;
        }
        else
            count += 1;
    }       
    tmp += count;
    return tmp.length() < iniString.length()?tmp : iniString;
}

书中提到用StringBuilder可以更加优化,但对此不是很熟悉,后续再补。

1.6 矩阵90度旋转(同LeetCode 48)

题目描述:有一副由NxN矩阵表示的图像,每个像素用一个int表示,在不占用额外内存空间的情况下(即不使用缓存矩阵),将图像顺时针旋转90度。

解法: 从最外层开始,向内逐层翻转矩阵元素。

def rotate(self, matrix):
    start = 0
    end = len(matrix) - 1
    while start < end: #控制每一层开始和结束的元素位置
        for i in range(start, end):
            tmp = matrix[i][end]
            #top -> right
            matrix[i][end] = matrix[start][i]
            #left -> top
            matrix[start][i] = matrix[end-i+start][start]
            #bottom -> left
            matrix[end-i+start][start] = matrix[end][end-i+start]
            #right -> bottom
            matrix[end][end-i+start] = tmp
        start += 1
        end -= 1

1.7 零矩阵(同LeetCode 73)

题目描述:若m*n矩阵中某个元素为0,则将其所在的行与列全部清零。

解法1: 遍历矩阵,存储矩阵元素为0的行号与列号,再将对应的行列元素全部置为0。

def setZeroes(self, matrix):
        tmp = []
        n = len(matrix)
        m = len(matrix[0])
        for i in xrange(n):
            for j in xrange(m):
                if matrix[i][j] == 0:
                    tmp.append([i, j])
        for index in tmp:
            for i in xrange(m):
                matrix[index[0]][i] = 0
            for j in xrange(n):
                matrix[j][index[1]] = 0

解法2: 直接用矩阵的第一行和第一列记录某列(行)中是否有零元素。

public void setZeroes(int[][] matrix) {
        boolean fr = false; //fr(fc)记录原有的第一行(列)是否有零元素
        boolean fc = false;//因为第一行或第一列的零元素都会由[0][0]记录
        for(int i = 0; i < matrix.length; i++)
        {
            for(int j = 0; j < matrix[0].length; j++)
            {
                if(matrix[i][j] == 0)
                {
                    if(i == 0)
                        fr = true;
                    if(j == 0)
                        fc = true;
                    matrix[i][0] = matrix[0][j] = 0;
                }
            }
        }
        for(int i = 1; i < matrix.length; i++)
        {
            for(int j = 1; j < matrix[0].length; j++)
            {
                if(matrix[i][0] == 0 || matrix[0][j] == 0)
                    matrix[i][j] = 0;
            }
        }
        if(fr)
        {
            for(int i = 0; i < matrix[0].length; i++)
                matrix[0][i] = 0;
        }
        if(fc)
        {
            for(int i = 0; i < matrix.length; i++)
                matrix[i][0] = 0;
        }
    }

1.8 字符串翻转

题目描述:假定已知isSubstring方法来检查一个单词是否为其他字符串的子串。给定两个字符串s1和s2,判断s2是否为s1旋转而成,要求只能调用一次isSubstring方法。

解法: 仅需要判断是否可将字符串s1分隔为两部分x和y,使得 xy = s1且 yx = s2。无论分割点在哪里,都存在yx是xyxy的子串,即s2为s1s1的子串。

public boolean checkReverseEqual(String s1, String s2) {
        if(s1.length() != s2.length())
            return false;
        String s3 = s1 + s1;
        return s3.contains(s2);
    }
程序员面试金典.Cracking the Coding Interview.第5版 英文版 书在手,面试机会我有 这本书详细讲解了般技术公司面试的流程,评价标准设置,最后还有个章节为你在薪水上讨价还价进行支招。 当然,书中最核心的还是面试中的题目了。本书的题目以算法和数据结构为主,但也分别有个章节涵盖分布式系统设计,c/c++、java、sql、多线程等知识性的内容。所有题目都有解答思路和答案算法题目的实现使用了java。只要有点java基础的同学,应该都可以看明白。 书中有习题使用了后缀树。后缀树这个特殊的结构在《算法导论》等众多书中都没有出现,可以在网上找到些计算生物学的课件。很多匹配字符串相关的问题都可以用后缀树或者广义后缀树给出个线性解法。但注意的是这个数据结构所占用的空间也是很大的。虽然些情况下可以优化到线性,但这种优化在些具体的问题中会改变问题的语意,因此不是任何时候都可以适用的。对后缀树和广义后缀树感兴趣可以参考http://book.douban.com/subject/1765938/,网上也可以找到些相关的课件 书中有”连续子序列最大和值“和”最长递增子序列“这样的题目。但是没有包含”连续子序列最大积值“这样的题目,并且”最长递增子序列“给出的解答不是最优的,这两个题目大家可以额外思考下,面试中也很常见。 另外,面试过程中也会遇到很多与系统相关的知识性的题目,如流水线、虚拟内存、进程线程、地址空间结构、异常处理、并发编程等等,这些内容可以参考《深入理解计算机系统》http://book.douban.com/subject/5407246/。 网络相关的内容可以参考《TCP/IP详解》卷http://book.douban.com/subject/1099252/。 些更具体的内容,如linux启动过程、linux文件系统原理、浏览器访问网址过程等,可以查看wikipedia相关页面,linux相关的内容可以访问鸟哥的私房菜基础篇的相关文章http://linux.vbird.org/linux_basic/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值