首页 > 其他分享 >线性表 - 数组与链表

线性表 - 数组与链表

时间:2024-01-23 09:35:00浏览次数:27  
标签:head ListNode 线性表 nums int next 链表 数组

感谢@pdai的全栈知识体系,数据结构与算法是相通的,做的题目与原博主不同。 https://www.pdai.tech/md/algorithm/alg-basic-array.html

数组

数组是一种连续存储线性结构,元素类型相同,大小相等,数组是多维的,通过使用整型索引值来访问他们的元素,数组尺寸不能改变。

数组的优点:

  • 存取速度快

数组的缺点:

  • 事先必须知道数组的长度
  • 插入删除元素很慢
  • 空间通常是有限制的
  • 需要大块连续的内存块

相关题目

简单难度

268. 丢失的数字 https://leetcode.cn/problems/missing-number/
class Solution {
    public int missingNumber(int[] nums) {
        // 人为添加0到n一共n+1个整数,将这些数和nums中所有数异或,则除了丢失的数,其余数字出现两次,得到结果
        int xor = 0;
        int n = nums.length;
        for(int i = 0; i < n; i++){
            xor ^= nums[i];
        }
        for(int i = 0; i <= n; i++){
            xor ^= i;
        }
        return xor;
    }
}

中等难度

16. 最接近的三数之和 https://leetcode.cn/problems/3sum-closest/
class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int n = nums.length;
        int best = Integer.MAX_VALUE;
        // 枚举 a
        for (int i = 0; i < n; ++i) {
            // 保证和上一次枚举的元素不相等
            if (i > 0 && nums[i] == nums[i-1]) {
                continue;
            }
            // 使用双指针枚举 b 和 c
            int j = i + 1, k = n - 1;
            while (j < k) {
                int sum = nums[i] + nums[j] + nums[k];
                // 如果和为 target 直接返回答案
                if (sum == target) {
                    return target;
                }
                // 根据差值的绝对值来更新答案
                if (Math.abs(sum - target) < Math.abs(best - target)) {
                    best = sum;
                }
                if (sum > target) {
                    // 如果和大于 target,移动 c 对应的指针
                    int k0 = k - 1;
                    // 移动到下一个不相等的元素
                    while (j < k0 && nums[k0] == nums[k]) {
                        --k0;
                    }
                    k = k0;
                } else {
                    // 如果和小于 target,移动 b 对应的指针
                    int j0 = j + 1;
                    // 移动到下一个不相等的元素
                    while (j0 < k && nums[j0] == nums[j]) {
                        ++j0;
                    }
                    j = j0;
                }  
            }
        }
        return best;
    }
}

链表

n 个节点离散分配空间,彼此通过指针相连,每个节点只有一个前驱节点,每个节点只有一个后续节点,首节点没有前驱,尾节点没有后继。确定一个链表我们只需要头指针,通过头指针就可以遍历整个链表。

优点

  • 空间没有限制
  • 插入删除元素很快

缺点

  • 存取速度很慢

分类

  • 单向链表:一个节点指向下一个节点
  • 双向链表:一个节点有两个指针域,一个指向后继,一个指向前驱
  • 循环链表:能通过任何一个节点找到其他所有的节点,将两种(双向/单向)链表的最后一个节点指向第一个节点从而实现循环。

节点创建代码

public class Node {
    // 数据域
    public int data;
    // 指针域,指向下一个节点
    public Node next;
    
    public Node() {
    }
    
    public Node(int data) {
        this.data = data;
    }
    public Node(int data, Node next) { 
        this.data = data;
        this.next = next;
    }
}

相关题目

链表是空节点,或者有一个值和指向下一个链表的指针,因此很多链表问题可以用递归来处理。

简单难度

234. 回文链表 https://leetcode.cn/problems/palindrome-linked-list/
class Solution {
    public boolean isPalindrome(ListNode head) {
        List<Integer> vals = new ArrayList<>();
        // 将链表的值复制到数组
        ListNode currentNode = head;
        while (currentNode != null) {
            vals.add(currentNode.val);
            currentNode = currentNode.next;
        }
        // 使用双指针判断是否回文
        int left = 0;
        int right = vals.size() - 1;
        while (left < right) {
            if (!vals.get(left).equals(vals.get(right))) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

中等难度

92. 反转链表 II https://leetcode.cn/problems/reverse-linked-list-ii/
class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        // 设置 dummyNode 是这一类问题的一般做法
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;
        ListNode pre = dummyNode;
        for (int i = 0; i < left - 1; i++) {
            pre = pre.next;
        }
        ListNode cur = pre.next;
        ListNode next;
        // 使用头插法实现链表反转
        for (int i = 0; i < right - left; i++) {
            next = cur.next;
            cur.next = next.next;
            next.next = pre.next;
            pre.next = next;
        }
        return dummyNode.next;
    }
}
148. 排序链表 https://leetcode.cn/problems/sort-list/
class Solution {
    public ListNode sortList(ListNode head) {
        return sortList(head, null);
    }
    // 快慢指针找到中间节点,两边分别进行排序,然后再进行归并排序
    public ListNode sortList(ListNode head, ListNode tail) {
        if (head == null) {
            return head;
        }
        if (head.next == tail) {
            head.next = null;
            return head;
        }
        ListNode slow = head, fast = head;
        while (fast != tail) {
            slow = slow.next;
            fast = fast.next;
            if (fast != tail) {
                fast = fast.next;
            }
        }
        ListNode mid = slow;
        ListNode list1 = sortList(head, mid);
        ListNode list2 = sortList(mid, tail);
        ListNode sorted = merge(list1, list2);
        return sorted;
    }
    public ListNode merge(ListNode head1, ListNode head2) {
        ListNode dummyHead = new ListNode(0);
        ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
        while (temp1 != null && temp2 != null) {
            if (temp1.val <= temp2.val) {
                temp.next = temp1;
                temp1 = temp1.next;
            } else {
                temp.next = temp2;
                temp2 = temp2.next;
            }
            temp = temp.next;
        }
        if (temp1 != null) {
            temp.next = temp1;
        } else if (temp2 != null) {
            temp.next = temp2;
        }
        return dummyHead.next;
    }
}

标签:head,ListNode,线性表,nums,int,next,链表,数组
From: https://www.cnblogs.com/understanding-friends/p/17981637

相关文章

  • STL-list链表
    STL-list链表目录STL-list链表初始化创建添加删除元素遍历迭代参考函数参考资料STL-list容器,又称双向链表容器,即该容器的底层是以双向链表的形式实现的。这意味着,list容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中。list容器中各个元素的......
  • awk数组使用
    群里看到有一个大哥需求计算当天的binlog大小,有一个大哥给出下面的shell脚本ls--full-time|grep^-|awk'{s[$6]+=$5}END{for(iins){printf("%s%0.2f\n",i,s[i]/1024/1024)}}'相关解释ls--full-time:ls是列出目录内容的命令、--full-time选项回显示文件和目录的完整时......
  • 利用指针打印数组内容
    #include<stdio.h>#include<assert.h>//因为只是读取数组的数据,而不需要做任何修改//所以我们给形参int*p前面修饰上一个const,以防写出BugvoidPrint_arr(constint*p,intsz){ assert(p); inti=0; for(i=0;i<sz;i++) { printf("%d",*(p+i)); }}......
  • 238.除自身以外数组的乘积
    1.题目介绍给你一个整数数组nums,返回数组answer,其中answer[i]等于nums中除nums[i]之外其余各元素的乘积。题目数据保证数组nums之中任意元素的全部前缀元素和后缀的乘积都在32位整数范围内。请不要使用除法,且在O(n)时间复杂度内完成此题。示例1:输入:nu......
  • 【glibc】glib库单向链表GSList介绍
    glib库单向链表介绍glib库里实现了一些基本的数据结构,比如单向链表,双向链表、队列、树、hash表和数组。这篇文章里我主要介绍在linux平台下使用glib库中的单向链表进行编程,以后的文章我会陆续介绍双向链表、队列和其它数据结构的用法。单向链表(即GSList)是glib库里最简单的容具,它......
  • 【glibc】glib 数组
    编译:gcc-g-Wall-O0fuck.c-ofuck`pkg-config--libs--cflagsglib-2.0`1基本操作这里是向数组添加和删除数据的一些主要方法:#include<glib.h>#include<stdio.h>intmain(intargc,char**argv){GArray*a=g_array_new(FALSE,FALSE,sizeof(char*));......
  • 【glibc】glib库双向链表GList介绍
    在上一篇文章里我介绍了glib库中单向链表的用法,这篇文章介绍glib库双向链表的用法,还是沿用上一篇文章的风格,采用在代码中加入注释来说明代码,最后贴出程序的运行结果,然后加以少量说明。双向链表与单向链表的区别是,从一个节点,不仅能访问到它的下一个节点,还能访问到它的上一个节点,其......
  • 【glibc】glib库数组GArray介绍
    glib库中的数组GArray类型很像C++标准容器库中的vector容器。要使用glib库中的数组中需要声明一个指向GArray类型的指针。GArray的定义如下:structGArray{gchar*data;guintlen;};然后就可以在这个数组前或者数组后添加数据,添加数据的时候数组也会像C++中的vector容器......
  • Go语言核心36讲 07 | 数组和切片
    从本篇文章开始,我们正式进入了模块2的学习。在这之前,我们已经聊了很多的Go语言和编程方面的基础知识,相信你已经对Go语言的开发环境配置、常用源码文件写法,以及程序实体(尤其是变量)及其相关的各种概念和编程技巧(比如类型推断、变量重声明、可重名变量、类型断言、类型转换、别名类......
  • 关于Java 数组
    了解Java数组Java中的数组是一种强大而灵活的数据结构,让我们一起深入探讨它的方方面面,从基础的概念到高级的应用。1.数组的创建与初始化首先,我们来看如何创建和初始化一个简单的整型数组:publicclassArrayExample{publicstaticvoidmain(String[]args){......