记录两道面试题:
题目描述:
输入一个链表,输出该链表中倒数第k个结点。(单向链表)
拿到这个问题的时候自然而然会想到让链表从末尾开始next K-1 次不就是第K-1个节点了么,但是必须要注意一点,这是单向链表。那么这时候的解决思路或许就会出现分歧,大多数人都会想到遍历一下链表,获取链表的长度,然后再减去 K 长度的节点,那么我们这个链表的最后一个节点就是原链表的倒数第K个节点:我们看一下实现代码:
/**
* 获取倒数第K个节点的数据
* @param index
* @return
*/
public int getDtae(int index){
//对整个链表进行遍历
int size = 0;
Node current = head;//head是头结点
while(current!=null){
size++;
current = current.next;
}
current = head;
//向后遍历size-K获取倒数第K个节点
for(int i = 0;i < size - index;i++){
current = current.next;
}
return current.date;
}
定义两个节点first和second,他们同时指向head头结点。我们先把第二个节点向后移动index-1步,这时first和second是不是就相距k,我们再把两个节点同时向后移动,当second到达链表尾端的时候,是不是就可以说first的位置就是我们需要的倒数第K个节点。(只遍历一次)
/**
* 获取倒数第K个节点的数据
* @param index
* @return
*/
public int getDtae(int index){
//判断index是否为零或者是小于零的不合法数据
if(index <= 0 || head == null){
//抛出空指针异常
throw new NullPointerException();
}
//定义两个节点指向head
Node first = head;
Node second = head;
//把第二个节点向后移动k-1步
for(int i = 0;i < index - 1;i++){
second = second.next;
}
//再把两个节点同时向后移动,直到second到达尾端位置
while(second!=null){
first = first.next;
second = second.next;
}
return first.date;
}
问题描述:
有一个1GB大小的文件,文件里面每一行是一个词,每个词的大小不超过16B,内存大小限制为1MB,要求返回频数最高的100个词。
分析:
由于文件大小为1GB,而内存的大小只有1MB,因此不能一次把所有的词读入到内存中去处理,可以采用分治的方法进行处理:把一个文件分解为多个小的子文件,从而保证每个文件的大小都小于1MB,进而可以直接被读取到内存中处理。
解题思路:
1、遍历文件,对遍历到的每一个词,执行Hash操作:hash(x)%2000,将结果为i的词存放到文件ai中,通过这个分解步骤,可以是每个子文件的大小约为400KB左右,如果这个操作后的文件大小超过1MB,那么可以使用同样的方法把文件继续进行分解下去,直到文件的大小小于1MB为止。2、统计出每个文件中出现频率最高的100个词。最简单的就是使用字典来实现,具体方法为:遍历文件中的所有词,对于遍历到的词,如果字典中不存在,则把这个词存入到字典中(键为这个词,值为1),如果这个词已经在字典中,那么把这个词对应的值加一。遍历后可以非常容易的找到出现频率最高的100个词。
3、上一步找出了每个文件中出现频率最高的100个词,这步可以通过维护一个小顶堆来找出所有词中出现频率最高的100个词。遍历第一个文件,把第一个文件中的出现频率最高的100个词构成一个小顶堆。(如果第一个文件中词的数目小于100,那么可以继续遍历第二个文件,直到构建好有100个节点的小顶堆为止)。继续遍历,如果遍历到的词的出现次数大于堆顶上词的出现次数,那么可以用新遍历到的词替换堆顶的词,然后重新调整这个堆为小顶堆。当遍历完所有的文件后,这个小顶堆中的词就是出现频率最高的100个词。当然这一步也可以采用类似归并排序的方法把所有文件中出现次数最高的100个词进行排序,最终找出出现次数最高的100个词。