(周末两天均在完善Json解析器与生成器,现如今可以腾出手来刷题)
题目名称
- 数字序列中某一位的数(剑指offer #44)
- 把数组排成最小的数(剑指offer #45)
- 把数字翻译成字符串(剑指offer #46)
- 礼物的最大价值(剑指offer #47)
- 最长不含重复字符的子字符串(剑指offer #48)
- 丑数(剑指offer #49)
- 第一个只出现一次的字符(剑指offer #50)
- 数组中的逆序对(剑指offer #51)
- 两个链表的第一个公共节点(剑指offer #52)
- 在排序数组中查找数字(剑指offer #53)
数字序列中某一位的数(剑指offer #44)
解题思路
寻找规律,首先明确当前输入在哪一个区段,然后根据偏移量完成求解。这道题毫无难点,就是写起来很不舒服。
解题方案
1 | class Solution { |
把数组排成最小的数(剑指offer #45)
解题思路
这道题的难点在于排序规律,而非组合。我们完全可以将所有数字变为字符串存入vector中,然后利用C++ STL 接收谓词作为排序规则的特性对该vector排序(排序规则为s1+s2<s2+s1
),最终将vector转为string即可。
解题方案
1 | class Solution { |
把数字翻译成字符串(剑指offer #46)
解题思路
动态规划问题,dp[i]=f[i]*dp[i-1]+g[i]*dp[i-2]。其中dp[i]为前i个字符所能构成的组合数。f[i]表征s[i-1]为数字且不为0,g[i]表征s[i-1]是否能与前一个字符构成组合。需要注意的是‘0‘略微繁琐,这是一道细节题。
解题方案
1 | class Solution { |
礼物的最大价值
解题思路
这又是一道典型的动态规划。但有所区别的是,这道题没必要设立m*n的矩阵来保存临时值。由于到达坐标(i,j)的格子时能够拿到的礼物的最大价值只依赖坐标为(i-1,j)与(i,j-1)的格子,因此只需要使用一个长度为n的一维数组即可,数组中前j个数字为f(i,0)直到f(i,j),后面的则为f(i-1,j)直到f(i-1,n-1)。
解题方案
1 | class Solution { |
最长不含重复字符的子字符串(剑指offer #48)
解题思路
这道题没必要使用动规。假设子串里含有重复字符,则父串必含有重复字符,单个子问题足以决定父问题,因此可以使用贪心。在动规中,单个子问题影响父问题,并不足以决定父问题。
从左向右扫描,当遇到重复字母时,以上一个重复字母的index+1作为搜索起始位置,复杂度为O(n)。
解题方案
1 | class Solution { |
丑数(剑指offer #49)
解题思路
将之前所有的丑数全部存储起来,并且额外保存factor2、3、5作为当前的丑数因子。若当前factorn为最小,则更新其为n*ugly[++indexn];
解题方案
1 | class Solution { |
第一个只出现一次的字符(剑指offer #50)
解题思路
用一个hashtable保存字符出现的次数,然后遍历字符串找到这个字符即可。
解题方案
1 | class Solution { |
数组中的逆序对
解题思路
采用归并排序的策略,其中递归基是beg==end。需要注意的地方在于,若前一半的元素i大于后一半的元素j,则此时存在逆序对的个数为后一般数组剩余元素数,此外,每一次计算后都需要对原有数组完成排序。
解题方案
1 | class Solution { |
两个链表的第一个公共节点(剑指offer #52)
解题思路
假定两个链表长度为a+n与b+n,n为共有部分,那么两个链表一起走a+b+n步后必然相遇,相遇点为第一个共同点或nullptr(n==0)。具体实现就是一旦走到绝地就转向别人的头部。
解题方案
1 | class Solution { |
在排序数组中查找数字(剑指offer #53)
解题思路
本质上就是实现STL算法:equal_range;
解题方案
1 | class Solution { |