004 | 线性表面试经典上

写在前面:纸上得来终觉浅,绝知此事要躬行!有人说学数据结构光看不练就是耍牛氓,通过这几天的练习,感觉看跟写真的是两码事,前者是面儿后者才是里。
  1. 若某表最常用的操作是在最后一个结点之后插入一个节点或删除最后一二个结点,则采用()省运算时间。
    A. 单链表
    B. 双链表
    C. 单循环链表
    D. 带头结点的双循环链表
    答案:D
    解析:单链表和双链表每次找到尾部都需要遍历整个链表,单循环链表是单向的,找到尾部也需要遍历整个链表!

  2. 构造线性表结点类,下面后续的练习都采用此类:

package link;

/**
 * User: ZhangQi
 * Date: 2019/3/8
 * Time: 9:52
 * Desc: 结点类
 */
public class ListNode {

    //数值域
    int val;
    //指针域
    ListNode next;

    public ListNode(int val) {
        this.val = val;
    }
    
}

  1. 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList
package link;

import java.util.ArrayList;

/**
 * User: ZhangQi
 * Date: 2019/3/8
 * Time: 9:57
 * Desc: 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList
 */
public class Solution {

    /**
     * 思路一:由于需要倒叙输出链表,所以第一时间想到的是反转链表然后在遍历取值
     */
    ArrayList<Integer> list = new ArrayList<>();
    public ArrayList<Integer> printListFromTailToHead1(ListNode listNode) {
        if(listNode == null) return list;

        ListNode next = null;
        ListNode pre = null;
        /** 反转链表 */
        while(listNode!=null){
            next = listNode.next;
            listNode.next = pre;
            pre = listNode;
            listNode = next;
        }
        /** 遍历反转后的链表取值 */
        while(pre!=null){
            list.add(pre.val);
            pre = pre.next;
        }
        return list;

    }

    /**
     * 思路2:由于单链表只能从前往后遍历,而需要是需要倒叙链表,也就是先进后出的场景,
     *        而从想到 栈结构 进而想到递归
     * @param listNode
     * @return
     */
    public ArrayList<Integer> printListFromTailToHead2(ListNode listNode) {
        if(listNode == null) return list;

        /** 使用递归必须要有一个退出条件 */
        if (listNode != null) {
            this.printListFromTailToHead2(listNode.next);
            list.add(listNode.val);
        }
        return list;

    }
    
}

  1. 输入一个链表,输出该链表中倒数第k个结点
package link;

/**
 * User: ZhangQi
 * Date: 2019/3/8
 * Time: 9:57
 * Desc: 输入一个链表,输出该链表中倒数第k个结点
 */
public class Solution {

    /**
     * 思路:定义快指针和慢指针,当快指针走到 k-1 步的时候,快,慢指针一起走,
     *       当快指针遍历完链表的时候,慢指针所在到结点就是倒数第k个结点率
     * @param head
     * @param k
     * @return
     */
    public ListNode FindKthToTail(ListNode head, int k) {

        if (head == null || k <= 0) return null;

        /** 初始化快,慢指针,使其指向头指针 */
        ListNode fast = head;
        ListNode show = head;
        
        /** 快指针先走,让其到达 k-1 结点处 */
        while (fast != null && k > 0) {
            fast = fast.next;
            k--;
        }
        /** 快慢一起走,直至快指针遍历完链表 */
        while (fast != null) {
            show = show.next;
            fast = fast.next;
        }
        /** 判断 k 值是否大于链表长度 */
        return k > 0 ? null : show;

    }

}

  1. 输入一个链表,反转链表后,输出新链表的表头
package link;

/**
 * User: ZhangQi
 * Date: 2019/3/8
 * Time: 9:57
 * Desc: 输入一个链表,反转链表后,输出新链表的表头
 */
public class Solution {

    /**
     * 思路:反转链表主要是对指针域进行转向操作
     * @param head
     * @return
     */
    public ListNode ReverseList(ListNode head) {

        ListNode newLink = null;
        ListNode next = null;
        while (head != null) {
            /** 记录下一个结点位置,避免遗失 */
            next = head.next;
            /** 反转指针域使其指向上一个结点 */
            head.next = newLink;
            /** 新链表向前进一步,这一步一定要在下一步之前完成 */
            newLink = head;
            /** 最后旧链表指针向前一步进行遍历 */
            head = next;
        }
        return newLink;
    }

}

### 线性表数据结构面试题汇总 线性表是一种基本的数据结构,在计算机科学领域具有重要地位。以下是关于线性表的一些常见面试题目及其解答: #### 1. **什么是线性表?** 线性表是由n(n≥0)个相同类型的元素构成的有限序列,可以为空表。其特点是每个元素都有唯一的前驱和后继[^3]。 #### 2. **线性表的特点是什么?** - 线性表中的数据元素是同一种类型。 - 每个元素有唯一的一个直接前驱和直接后继(除了首尾两个特殊位置)。 - 线性表支持随机访问操作,即可以通过索引快速定位某个元素的位置[^1]。 #### 3. **线性表有哪些存储方式?** 线性表有两种主要的存储方式:顺序存储和链式存储。 - **顺序存储**:通过数组实现,优点是可以快速按位查找;缺点是在插入删除时可能需要移动大量元素。 - **链式存储**:通过指针连接节点来表示逻辑上的前后关系,适合频繁增删场景下的应用。 #### 4. **如何判断单链表是否有环?** 使用双指针法(快慢指针)。定义两个指针slow和fast,初始都指向头结点head。每次迭代中,让slow向前走一步而fast则前进两步。如果存在环,则这两个指针最终会相遇;否则当fast到达null时表示无环。 ```python def has_cycle(head): slow, fast = head, head while fast and fast.next: slow = slow.next # 移动一次 fast = fast.next.next # 移动两次 if slow == fast: # 如果相等说明成环 return True return False # 走到最后都没有遇到重复节点代表不成环 ``` #### 5. **已知一个带头结点的单向循环链表L,设计算法求出该链表长度len(L)** 设p为工作指针,初始化计数值count=0并令p=L->next; 当p不等于L时执行如下操作直到条件满足为止——使p=p->next并将count加一;最后返回count即可得到整个列表的实际大小。 ```c++ int Length(LinkList L){ int count=0; LinkNode *p=L->next; while(p != NULL && p!=L ){ ++count ; p=p->next ; } return count; } ``` #### 6. **给定一个整数k以及一个含有N个不同正整数的有序数组arr[] ,请编写函数找出所有差值绝对值小于等于K 的数对数目 。** 采用滑动窗口技术解决此问题。先设定左边界left=right=0 ,再逐步增大右端直至找到符合条件的最大区间[right-left+1];接着更新答案ans += (right - left); 最后再把左侧收缩至仍保持有效状态的位置处继续上述过程直至遍历结束[^2]. ```java public static long findPairs(int [] nums,int k){ Arrays.sort(nums); long res = 0l; int n =nums.length; int j=0; for(int i=0;i<n;++i){ if(i>0&&nums[i]==nums[i-1]) continue;//去重处理 while(j<i&&(long)Math.abs((double)(nums[j]-nums[i]))<=k )j++; res+=Math.max(0,j-i-1); } return res; } ``` --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值