善用信息进行优化的算法面试题例举

本文通过两个具体案例介绍如何在算法设计中充分利用已知信息进行优化。第一个案例是利用年龄范围特性,采用hashtable来高效地对百度公司员工按年龄排序;第二个案例是通过巧妙的数据处理方法,在数组中快速找到出现次数超过半数的元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1)百度公司有3万名员工,请按照年龄对员工进行排序。

本题可以用认为是一个排序算法的问题。但如果简单的这么认为,那么算法优化时就没能很好的利用已有的信息。

由于年龄有一定的范围,所以可以根据这个特点来优化。

我们假设年龄在0-100这个范围之内。这样可以用一个hash table(这里可以简化为一个数组)来表示这个信息。

数组的下标可以为年龄,数组的值则可以记录这个年龄的人数。这样就起到了一个key-value的hash table的作用。

具体代码如下:

def sortAges(ages):
    length = len(ages)
    assert(length > 0)
    
    innerAges = [ ]  #用来记录年龄的hash table
    for i in range(1, 100): # 初始化的值全0
        innerAges.append(0)

    for it in ages:    #统计当前的数组中各个年龄的人数
        assert(0< it <100)
        innerAges[it] += 1
        
    for i in range(len(innerAges)): # 注意这里i来表达的时实际的年龄,innerAges[i] 则表达了这个年龄的人数
        if innerAges[i] > 0:             
            for j in range(innerAges[i]): # 输出i 年龄段的人数
                print(i)

# Test Case
ages = [25, 26, 22, 20, 19, 34, 32, 80, 32, 35, 30, 25, 26, 22, 20, 19, 34, 32, 30, 30, 19, 19]
sortAges(ages)

 

2) 寻找“灌水王”,论坛里有个人发的贴子超过了半数,请找出这个人的ID。

我们可以把这个问题简化成一个数组中有个数,出现的次数超过了半数,然后找出它来。

这样问题就好解决了。可以统计出每个数出现的个数,然后找出个数超过半数的即可,但这么做效率太低。

我们利用已有的条件,这个数超过了半数,如果我们每次将这个数和其他数进行各自一半的去除,则最后留下来的数一定

是超过半数的数。具体来说:我们先给某个数赋个初值,如果下一个数等于这个数,将其个数+1,如果不是这个数,

则将其个数-1,当前个数为0时,则用下一个数来取代这个数。这个过程尝试于将这个数与其他数每次各自-1,

这样做如果这个数超过半数,所以最后剩下的总是这个数。

具体代码实现如下:

def findSpecialNum(array):
    """
    在一组数种寻找超过半数的数字
    """
    num = array[0]
    count = 1
    for i in range(1, len(array)):
        #print("checking ", num, array[i])
        if count == 0:
            num = array[i]
            count = 1
        if array[i] != num:
            count -= 1
        else:
            count += 1
        #print(count)
        
    count = 0
    for i in array:
        if num == i:
            count += 1
    if count*2 > len(array):  # 由于输入可能不合法,这里需要做一次检查
        return num
    else:
        print("Didn't get the num")
        return None

if __name__ == "__main__":
    a = [1,2,1,3,1,1,1,1,-2,6,1,1,1,9,-1,8,1,1,1,2,-1,1,-1,2,5,9,8,1,1,1,1,2,2,2,2,22,22,2,1,1,1,1,1,1,1,1,1,1,1,1,1]
    print(findSpecialNum(a))

这两个例子很好的说明了在算法优化过程中,对已知信息善加利用的重要性!

 

 

<think>嗯,用户让我介绍一下对链表的理解。首先,我得回忆一下链表的基本概念。链表是一种线性数据结构,对吧?和数组不同,链表中的元素不是连续存储的。每个元素叫做节点,节点里包含数据和指向下一个节点的指针。这样的话,链表通过指针连接各个节点,形成链式结构。 那链表和数组的区别呢?数组需要连续内存空间,插入删除元素时可能需要移动其他元素,时间复杂度高。而链表在插入删除时只需要改变指针,效率更高。不过链表访问元素需要从头开始遍历,不能像数组那样随机访问,时间复杂度是O(n)。 接下来得考虑链表的类型。最常见的应该是单链表,每个节点只有一个指针指向下一个节点。然后是双向链表,每个节点有前驱和后继两个指针,可以双向遍历,方便逆向操作,但占用更多内存。还有循环链表,尾节点指向头节点,形成一个环,适合需要循环访问的场景。 链表的操作,比如创建、插入、删除、遍历这些基本操作。插入和删除的时候要注意指针的调整顺序,避免断链。比如在单链表中插入节点,需要先让新节点指向下一个节点,再让前一个节点指向新节点,否则会丢失后面的节点。 还有链表的内存管理。链表动态分配内存,不需要预先知道数据规模,可以灵活扩展。但每个节点需要额外的指针空间,内存开销比数组大。另外,频繁的插入删除会导致内存碎片,不过现代内存管理机制可能优化了这一点。 应用场景方面,链表适合频繁插入删除的情况,比如实现队列、栈、哈希表的冲突链、图的邻接表等。在操作系统里,进程控制块可能用链表管理。还有LRU缓存淘汰算法,用双向链表快速移动节点。 可能需要注意的问题,比如边界条件处理。比如头节点和尾节点的操作容易出错,插入删除时链表为空或者只有一个节点的情况需要特别处理。还有循环链表容易陷入死循环,遍历时要设置终止条件。 最后,链表的优缺点总结。优点:动态大小,灵活的内存使用,高效的插入删除。缺点:无法随机访问,内存开销大,缓存不友好,因为节点分散存储,访问效率可能不如数组。 用户可能需要了解链表的基础,或者对比其他数据结构,或者准备面试题。所以应该详细说明结构、操作、类型、应用,以及注意事项。结构清晰的话,分点回答比较合适,可能还需要举例子,比如插入节点的步骤,用LaTeX公式展示指针的变化。不过用户要求用中文回答,所以例子要简单明了,避免太技术化的术语,但保持准确性。</think>$$链表结构示意图:\quad node \rightarrow [数据|指针] \rightarrow node \rightarrow \cdots \rightarrow null$$ 我对链表的理解可归纳为以下几个层次: 一、基础结构特性 1. **节点组成**:每个节点包含$data$和$next$指针,双向链表还包含$prev$指针 2. **动态内存**:内存非连续分布,通过指针实现逻辑上的线性关系 3. **头尾标识**:需维护头节点(head)和尾节点(tail),循环链表尾节点指向头节点 二、核心操作复杂度 $$时间复杂度\begin{cases} 访问:O(n)\\ 插入/删除:O(1)\ (已知位置时)\\ 搜索:O(n) \end{cases}$$ 三、类型对比 | 类型 | 指针数量 | 特点 | 典型应用 | |-----------|------|---------------------|----------------| | 单链表 | 1 | 单向遍历 | 简单数据存储 | | 双向链表 | 2 | 支持双向遍历,内存开销增加 | 浏览器历史记录 | | 循环链表 | 1/2 | 尾节点指向头节点 | 轮询调度系统 | 四、关键操作实现 1. **插入节点**(单链表示例): ```python # 在节点A后插入新节点B B.next = A.next A.next = B ``` 2. **删除节点**: ```python # 删除A的后继节点 target = A.next A.next = target.next target.next = null ``` 五、应用场景 1. 操作系统:文件系统目录结构 2. 算法设计:LRU缓存淘汰算法($$O(1)$$复杂度实现) 3. 基础结构:栈/队列的链式实现 六、优劣分析 ✓ **优势**: - 动态空间分配避免内存浪费 - 高效处理头尾操作(尤其双向链表) - 无需预知数据规模 ✗ **劣势**: - 额外指针占用内存空间(每个节点增加$30\%-50\%$开销) - 缓存不友好(空间局部性差) - 反向遍历成本高(单链表需$O(n^2)$时间) 理解链表的关键在于掌握指针操作的精髓,注意处理边界条件(如空链表、单节点链表),并善用虚拟头节点(dummy node)简化操作。在解决实际问题时,常结合快慢指针、递归等技巧,例如检测环形链表: $$设快指针速度v_f=2,\ 慢指针v_s=1,\ 若存在环必相遇$$
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值