1.1 实现一个算法,确定一个字符串的所有字符是否全都不同。不允许使用额外的数据结构。

解答:这里假定字符集为ASCII码,可以与面试官沟通确认字符串使用的字符集。由于字符集是有限的,建立一个数组模拟的Hash表记录每个字符是否出现,线性扫描一次字符串即可,复杂度O(len(s)).如果字符集较大,需要考虑空间开销,则可以用bitset来实现。

 1 bool isUnique(string s) {
 2   bool record[256];
 3   memset(record, 0, sizeof(record));
 4   size_t size = s.size();
 5   for(size_t i = 0; i < size; ++i) {
 6     if (record[s[i]] == true)
 7       return false;
 8     else
 9       record[s[i]] = false;
10   }
11   return true;
12 }

可以加一个剪枝:如果字符串的大小大于字符集的大小了,那么该字符串肯定是存在重复字符的。

 1 bool isUnique(string s) {
 2     size_t size = s.size();
 3     if (size > 256)
 4             return false;
 5    bool record[256];
 6    memset(record, 0, sizeof(record));
 7    for(size_t i = 0; i < size; ++i) {
 8      if (record[s[i]] == true)
 9        return false;
10      else
11        record[s[i]] = false;
12    }
13    return true;
14 }

补充:假设对空间开销非常严苛,可以考虑先对字符串中的字符排序,然后进行一次线性扫描;如果还不允许改变字符串原有的内容,那么就只能暴力搜查了吧。


1.2 用C或C++实现void reverse(char * str)函数,即反转一个‘\0’结尾的字符串。

解答

 1 void reverse(char *str) {
 2     if (str == nullptr) return;
 3     size_t length = strlen(str);
 4     for (size_t i = 0; i < length / 2; ++i) {
 5         // swap str[i] and str[length - 1 - i];
 6         char temp = str[i];
 7         str[i] = str[length - 1 - i];
 8         str[length - 1 - i] = temp;
 9     }
10 }    


1.3 给定两个字符串,请写程序,确定其中一个字符串的重新排列后,能否变成另一个字符串。

解答:这里同样假定字符集是ASCII码,假定判断字符串相等时,大小写是区分的。在开始时通过检查两个字符串长度是否相等进行剪枝,然后,用一个数组记录第一个字符串中每个字符出现的次数,然后判断第二个字符串中每个字符出现的次数是否与第一个字符串相等即可。

 1 bool canConvert(string s1, string s2) {
 2     if (s1.size() != s2.size())
 3         return false;
 4     int record[256];
 5     memset(record, 0, sizeof(record));
 6     for (auto &c : s1) {
 7         ++record[c];
 8     }
 9     for (auto &c : s2) {
10         if (--record[c] < 0)
11             return false;
12     }
13     return true;
14 }


1.4 编写一个方法,将字符串中的空格全部替换为"%20".假定字符串尾部有足够的空间存放新增字符,并且知道字符串的真实长度。示例:

输入: "Mr John Smith"

输出: "Mr%20John%20Smith"

解答:需要改变字符串长度的问题,通常从尾部开始处理比较高效,因为可以避免字符的重复移动。

 1 void replaceSpace(char str[], int length) {
 2     //length为字符串实际长度,不包括结尾的'\0'
 3     if(length <= 0) return;
 4     int space_cnt = 0;
 5     for (int i = 0; i < length; ++i) {
 6         if (str[i] == ' ') {
 7             ++space_cnt;
 8         }
 9     }
10     if (space_cnt > 0) {
11         int j = length + space_cnt * 2;
12         str[j] = '\0';
13         for (int i = length - 1; i >= 0; --i) {
14             if (str[i] == ' ') {
15                 //用"%20"替换空格
16                 str[--j] = '0';
17                 str[--j] = '2';
18                 str[--j] = '%';
19             } else {
20                 str[--j] = str[i];
21             }
22         }
23     }
24 }


1.5 利用字符重复出现的次数,编写一个方法,实现基本的字符串压缩功能。比如:字符串"aabbcccccaaa"会变为"a2b1c5a3".若压缩后的字符串没有变短,则返回原先的字符串。

解答:重复长度编码(run length encoding, RLE).按照题述模拟即可,但要注意细节实现。(其中to_string(int)函数为C++11新增)

 1 string compress(string s) {
 2     string ret;
 3     int length = s.size();
 4     if (length > 0) {
 5         char buf = s[0];
 6         int cnt = 1;
 7         for (size_t i = 1; i < length; ++i) {
 8             if (s[i] != buf) {
 9                 ret = ret + buf + to_string(cnt);
10                 buf = s[i];
11                 cnt = 1;
12             }
13             else {
14                 ++cnt;
15             }
16         }
17         //开始忘记了加这一句,导致最后一组计数结果没有加入ret
18         ret = ret + buf + to_string(cnt);
19     }
20     //注意这里要加等号
21     return ret.size() >= s.size() ? s : ret;
22 }


1.6 给定一副NxN矩阵表示的图像,其中每个图像的大小为4字节,编写一个方法,将图像旋转90°。不占用额外空间能否做到?

解答:常见的问题了,有很多旋转的方式,这里就用最常用的由外向内逐层旋转的方法吧。

这里需要特别注意旋转过程中的循环停止条件和对应的坐标,不小心非常容易出错,用含义清晰的变量名有利于理清思路,避免错误。

 1 void rotate(int **matrix, int n) {
 2     for (int layer = 0; layer < n / 2; ++layer) {
 3         int last = n - 1 - layer;
 4         for (int j = layer; j < last; ++j) {
 5             int offset = j - layer;
 6             //保存上
 7             int temp = matrix[layer][j];
 8             //左->上
 9             matrix[layer][j] = matrix[last - offset][layer];
10             //下->左
11             matrix[last - offset][layer] = matrix[last][last - offset];
12             //右->下
13             matrix[last][last - offset] = matrix[j][last];
14             //上->右
15             matrix[j][last] = temp;
16         }
17     }
18 }

另外关于参数传递的问题,这里需要的是一个可变长的二维数组,C++中我们只能通过传递一个二级指针来实现,这样在函数调用的时候就需要一些处理了:

1 int main(void) {
2     int arr1[] = { 1, 2, 3, 4 };
3     int arr2[] = { 5, 6, 7, 8 };
4     int arr3[] = { 9, 10, 11, 12 };
5     int arr4[] = { 13, 14, 15, 16 };
6     int *matrix[4] = { arr1, arr2, arr3, arr4 };
7     rotate(matrix, 4);
8     return 0;
9 }

C++中不能直接给函数传递二维数组的原因是:“数组名被改写成一个指针参数”规则并不是递归定义的。数组的数组会被改写成“数组的指针”,而不是“指针的指针”。


1.7 编写一个算法,若MxN的矩阵中某个元素为0,则将其所在的行与列都清零。

解答:LeetCode上也有这道题。可以用一个长度为M的数组和一个长度为N的数组分别记录有0的行和列。此外也可以利用矩阵本身的存储空间,用其中的一行一列来记录该结果。以下代码基于后一种方法。

 1 void setZero(int **matrix, int m, int n) {
 2     bool r1_zero = false, c1_zero = false;    //两个变量记录第一行和第一列是否含0
 3     //检查第一行
 4     for (int j = 0; j < n; ++j) {
 5         if (matrix[0][j] == 0) {
 6             r1_zero = true;
 7             break;
 8         }
 9     }
10     //检查第一列
11     for (int i = 0; i < m; ++i) {
12         if (matrix[i][0] == 0) {
13             c1_zero = true;
14             break;
15         }
16     }
17     //检查剩余元素
18     for (int i = 1; i < m; ++i) {
19         for (int j = 1; j < n; ++j) {
20             if (matrix[i][j] == 0) {
21                 //将元素是否为0记录到第一行和第一列
22                 matrix[0][j] = matrix[i][0] = 0;
23             }
24         }
25     }
26     //矩阵按规则置0
27     for (int i = 1; i < m; ++i) {
28         if (matrix[i][0] == 0) {
29             for (int j = 1; j < n; ++j) {
30                 matrix[i][j] = 0;
31             }
32         }
33     }
34     for (int j = 1; j < n; ++j) {
35         if (matrix[0][j] == 0) {
36             for (int i = 0; i < m; ++i) {
37                 matrix[i][j] = 0;
38             }
39         }
40     }
41     if (r1_zero) {
42         for (int j = 0; j < n; ++j) {
43             matrix[0][j] = 0;
44         }
45     }
46     if (c1_zero) {
47         for (int i = 0; i < m; ++i) {
48             matrix[i][0] = 0;
49         }
50     }
51 }


1.8 假定有一个方法isSubstring,可检查一个单词是否为其他字符串的子串。给定两个字符串s1和s2.请编写代码检查s2是否为s1旋转而成,要求只能调用一次isSubstring.(比如:waterbottle是erbottlewat旋转后的字符串)

解答:s2是s1经过一次旋转得到的,那么s1+s1拼成的字符一定把s2包含在其中。可以先判断两个字符串的长度是否相等。

1 bool isSubstring(string s1, string s2);   //s2是s1的子串是为真
2
3 bool isRotation(string s1, string s2) {
4     if (s1.size() == s2.size() && isSubstring(s1 + s1, s2) {
5         return true;
6     } else {
7         return false;
8     }
9 }


补充:第四版中的习题

1.3 设计算法并编码实现:在不使用额外缓冲区的情况下去除字符串中的重复字符。设计一些测试用例。

解答:如果允许开辟与字符串长度无关大小的数组,则可以用一个记录字符是否出现过的数组来实现。

 1 void removeDuplicate(char str[]) {
 2     int length = strlen(str);
 3     if (length > 1) {
 4         bool flag[256];
 5         memset(flag, 0, sizeof(flag));
 6         for (int i = 0, j = 0; i < length; ++i) {
 7             if (flag[str[i]] == false) {
 8                 flag[str[i]] = true;
 9                 str[j++] = str[i];
10             }
11         }
12         //不要忘记加上结束标志
13         str[length] = '\0';
14     }
15 }

如果不允许使用额外的数组来记录字符是否出现,那么就只有暴力搜查了。

 1 void removeDuplicate(char str[]) {
 2     int length = strlen(str);
 3     if (length > 1) {
 4         int k = 0;
 5         for (int i = 0; i < length; ++i) {
 6             bool found = false;
 7             for (int j = 0; j < k; ++j) {
 8                 if (str[i] == str[j]) {
 9                     found = true;
10                     break;
11                 }
12             }
13             if (!found) {
14                 str[k++] = str[i];
15             }
16         }
17         //不要忘记结束标记
18         str[k] = '\0';
19     }
20 }

测试用例如:"", "a", "aaa", "abab", "aabb", "abbbb", "abcd"...

转载于:https://www.cnblogs.com/dengeven/p/3735608.html

【Cracking the Code Interview(5th edition)】一、数组与字符串(C++)相关推荐

  1. 《C++ Primer (5th Edition)》笔记-Part IV. Advanced Topics

    注:本文以<C++ Primer(英文版)>(5th Edition)为参考. 总共由四部分组成: <C++ Primer (5th Edition)>笔记-Part I. T ...

  2. Cracking the coding interview

    转自:http://hawstein.com/posts/ctci-solutions-contents.html Cracking the coding interview--问题与解答 March ...

  3. C++ Primer - 5th Edition - 书中源代码 - 课后习题答案

    C++ Primer - 5th Edition - 书中源代码 - 课后习题答案 C++ Primer - 5th Edition - 书中源代码 - 课后习题答案 1. C++ Primer, 5 ...

  4. PHP and MySQL Web Development 5th Edition

    PHP and MySQL Web Development, 5th Edition 本书描述 使用php和mysql构建数据库驱动web应用程序的最终指南. PHP和MySQL是流行的开源技术,它们 ...

  5. 经典算法题目:Cracking the coding interview 问题与解答

    Cracking the coding interview--问题与解答 March 14, 2013 作者:Hawstein 出处: http://hawstein.com/posts/ctci-s ...

  6. [Free] Cracking the Coding Interview 6th Download

    [Free] Cracking the Coding Interview 6th Download 推荐给有梯子的童鞋们! https://www.pdfdrive.com/cracking-the- ...

  7. Illustrated C# 7, 5th Edition 免积分下载

    图书说明: 快速使用C#,使用独特的简洁和可视化格式来呈现C#7.0语言.无论您是第一次掌握C#还是努力加深理解,您都会发现本书对语言的各个方面都是清晰而新颖的. 数字在本书中是最重要的.在教授编程研 ...

  8. java字符串拆分成数组_用Java实现JVM第八章《数组和字符串》

    小傅哥 | https://bugstack.cn 沉淀.分享.成长,专注于原创专题案例,以最易学习编程的方式分享知识,让自己和他人都能有所收获.目前已完成的专题有:Netty4.x实战专题案例.用J ...

  9. c++ new 数组_用Java实现JVM第八章《数组和字符串》

    案例介绍 本章主要介绍如何实现让虚拟机处理数组和字符串,在虚拟机功能增强后,我们可以执行数组类型计算和输出字符串.本章需要新增实现数组指令:newarray.anewarray.arraylength ...

最新文章

  1. 常用的遍历文件夹批处理命令
  2. CF1120D Power Tree(树形DP/构造+差分+最小生成树)
  3. 「镁客·请讲」南京布塔:用动作捕捉世界的精彩
  4. paip.python错误解决12
  5. 重启Windows的PowerShell
  6. matlab势场动态栅格路径规划,融栅格法和人工势场法的机器人三维路径规划
  7. 什么是ctfmon.exe,为什么运行?
  8. 城通网盘仿蓝奏网盘源码 附带视频教程
  9. HTML label标签用法介绍
  10. 图片放大不失真 —— 矢量图
  11. 配合理lcd的c语言小游戏,51单片机+LCD12864做的贪食蛇和俄罗斯方块小游戏分享
  12. Java程序员应该搞懂的六个问题
  13. 安利自己读CS博士的鸡汤
  14. ActiveReportsJS3.0 详解 ActiveReportsJS3.X
  15. 河南对口计算机本科学校有哪些,河南省 2017 年普通高等学校对口招收中等职业学校毕业生考试-计算机类基础课参考答案...
  16. 基于51单片机 + ds12c887 + ds18b20 + lcd1602的时钟温度显示器(带闹钟功能)
  17. RT-Thread实战笔记|MPU6050使用详解及DMP姿态解算
  18. 手把手教你微软的Visual Studio 2022社区版编程工具安装和使用(图文详解)
  19. WheelTec ROS 机器人小车 ROS2 编码编译解决
  20. JVM第四篇之益处、常用java工具

热门文章

  1. RedHat7.0启动后黑屏
  2. 简单的错觉画_错觉图片生成实验 - 正方形错觉
  3. 计算机学院张旭豪,饿了么收购百度外卖,可以看出张旭豪硕士研究生是有多厉害!...
  4. php创建mysql计划任务_有关创建PHP-MySQL后台任务的建议
  5. python 手机测试_python脚本如何测试手机
  6. priorityqueue 的 add和offer方法有区别吗_日常在家安吉白茶应该如何去保存?城市与农村存放的方法有区别吗...
  7. 在html中加动画效果,html5中css3新添加的动画效果
  8. red hat 6 安装php,Red hat linux服务器简明安装手册(OpenSSL+Mysql+Apache2+PHP)
  9. 移动端安全测试主要涉及_移动端测试之Monkey操作事件和参数
  10. 从零开始搭建spring-cloud(5) ----config