《剑指offer》笔记-第5章(5)

来源:互联网 发布:大商创开源破解版源码 编辑:程序博客网 时间:2024/05/16 04:28

面试题50:第一个只出现一次的字符

题目一:实现函数,找出字符串中第一个只出现一次的字符,如“abaccdeff”,输出b

测试用例:

     功能测试:字符串所有字符都出现多次;字符串中所有字符都出现一次;字符串中存在只出现一次的字符;

     特殊输入:字符串为null;

分析:

     1.    从头扫描字符,拿到一个字符后,与其后面的字符比较,如果没有重复的字符,则它是第一个出现一次的字符;时间复杂度是O(n^2);

     2.    以空间换时间,用一个数组(哈希表)存放每个字符出现的次数;数组的下标是字符的ASCII值(char的长度是8bit,一共有256中字符,数组的大小是256);空间大小即辅助数组大小是常数,因此空间复杂度是O(1);

     3.    第一次扫描,填写辅助数组,时间复杂度O(n);

     4.    第二次扫描,找出第一个次数是1的字符,时间复杂度是O(n);一共时间复杂度是O(n);

可以用相似方法解决的题目:

     1.    从第一个字符串中删除在第二个字符串中出现过的所有字符。

     2.    删除字符串中所有重复出现的字符。

     3.    变位词:两个单词中出现的子相同,出现次数也相同,如evil和live;实现函数,判断输入的两个字符串是否是互为变位词。

题目二:实现函数,找出字符流中第一个只出现一次的字符。字符只能一个接着一个从字符流中读出。

测试用例:

     功能测试:读入一个字符;读入多个字符;读入的所有字符都是唯一的;读入所有字符都是重复的;

     特殊输入:读入0个字符;

分析:

     1.    用一个数组occurrence[256](哈希表)存放字符在字符流中的位置;数组的下标是字符的ASCII值(char的长度是8bit,一共有256中字符,数组的大小是256);

     2.    数组初始化为-1,如果字符第一次出现,则将occurrence[i]更新为字符在字符流中的位置;如果字符不是第一次出现,则将occurrence[i]更新为-2;

     3.    当需要找出到目前位置从字符流中读出的所有字符中第一个不重复字符时,扫描数组occurrence[256],找到最小的大于等于0的值;

面试题51:数组中的逆序对

     实现函数,输入一个数组,找出这个数组中的逆序对的总数。

测试用例:

     功能测试:递增排序的数组;递减排序的数组;包含重复数字的数组;未排序数组;

     边界测试:数组中只有两个数字;数组中只有一个数字;

     特殊输入:数组未null;

分析:

     1.    如果对每个数字,与其后的数字比较,计算出逆序对数目,时间复杂度是O(n^2);

     2.    统计逆序对的数目与归并排序的思路相似:将数组平均分成两部分,统计左半部分的逆序数并排序,统计右半部分的逆序数并排序;将左右两部分合并,统计逆序数并排序;这是一个递归过程;

     3.    合并左右两部分的方法是从后往前复制:维护3个指针,p1最初指向左半部分最大值,p2最初指向右半部分最大值,p3指向合并数组的将要插入的位置,最初指向最右侧;*p1如果大于*p2,则说明逆序对数增加右半部分*p2往前到第一个数字的数字个数,*p3=*p1,p1前移一位;*p1如果小于等于*p2,逆序数不增加,*p3=*p2,p2前移一位;直到p1移出左半部分边界或p2移除右半部分边界;

     4.    最后将剩余左半部分或右半部分的数字加入到合并数组中,返回的逆序数是左半部分逆序数+右半部分逆序数+新增加的逆序数

面试题52:两个链表的第一个公共节点

     实现函数,输入两个链表,找出它们的第一个公共节点。

     链表定义:Struct ListNode{ int m_nKey; ListNode* m_pNext;}

测试用例:

     功能测试:两个链表有公共节点;两个链表没有公共节点;第一个公共节点是链表的头节点;第一个公共节点在链表中间;第一个公共节点在链表尾;

     特殊输入:链表头节点是null;

分析:

     1.    链表是单向的,从第一个公共节点往后,链表是重叠的,拓扑形状是一个Y的形状;

     2.    如果从后往前找到最后一个公共相同节点就是第一个第一个公共节点;需要两个辅助栈,将两个链表的节点分别放入两个辅助栈中;比较栈顶的节点,相同则弹出,比较下一个,直到最后一个相同节点;空间复杂度是O(m+n),时间复杂度是O(m+n);

     3.    另一种方法:第一次遍历,遍历两个链表,得到两个链表的长度;第二次遍历,较长的链表先走若干步,同时遍历两个链表,直到遇到相同的节点,就是第一个公共节点;时间复杂都市O(m+n);

5.4总结

     面试对时间复杂度和空间复杂度都有要求,通常更关注时间复杂度;

     降低时间复杂度的方法有:寻找更高效的算法;以空间换时间;

     以空间换时间要注意辅助空间的大小,关注问题的背景,嵌入式开发要注意空间的消耗;

 


原创粉丝点击