Cracking the Coding Interview习题总结(一)

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);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值