162.寻找峰值221.最大正方形179.最大数138.复制带随机指针的链表695.岛屿的最大面积426.二叉搜索树与双向链表209.长度最小的子数组24.两两交换链表中的节点

本文介绍了四种算法问题的解决方案,包括使用二分搜索找到数组中的峰值元素,动态规划求解二维矩阵内最大正方形的面积,通过特定方法构造最大数,以及解决复制带有随机指针链表的难题。此外,还讨论了如何找到二叉搜索树中最大岛屿的面积和将其转化为双向链表的技巧。这些问题涉及数组、链表、二叉树等多种数据结构和算法,展示了在解决复杂问题时的策略和思考过程。
摘要由CSDN通过智能技术生成

162.寻找峰值

峰值元素是指其值严格大于左右相邻值的元素。给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。你可以假设 nums[-1] = nums[n] = -∞ 。

输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5

  1. 二分搜索。注意题目说了可以认为数组两边端点是山脚,意味着峰值点一定是存在的。查找时只需要沿着山顶方向找,该点到任意一边的端点一定存在峰值点

221.最大正方形

在一个由 '0''1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。

输入:matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]]
输出:4

  1. 动规。直接在原数组上维护更新dp表,dp[i][j]表示以matrix[i][j]为正方形右下角端点的最大正方形的边长。则当matrix[i][j]不等于’0’时,发生状态转移方程:

    matrix[i][j]=Math.min(matrix[i-1][j],matrix[i][j-1],matrix[i-1][j-1])+1

179.最大数

给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。

注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。

输入:nums = [3,30,34,5,9]
输出:“9534330”

  1. 这道题有点像基数排序,都是根据每个数每一位上进行比较判断。两个数字最高位不同时更大的排在前面,相同时则分别比较次高位。当两个数字的长度不同并且某一个数比较到最末位时,此时需要把另一个数接到该数的末尾继续进行位上数字的比较,举个例子[432,43243],比较到末尾时应该自动补足成43243243和43243432进行比较。注意仅当初始元素的长度不相等且比较到末位才能够用补足的方法**,对于完全相等的两个数不能补足。因为比较时需要任意访问每一位上的数,可以先把int类型元素转化成StringBuilder类型再进行比较。
public String largestNumber(int[] nums) {
    StringBuilder res=new StringBuilder();
    int p=0,max=0;
    boolean zero=true;
    for(int i=0;i<nums.length;i++) 
        if(nums[i]!=0) zero=false;
    if(zero==true) return res.append("0").toString();
    StringBuilder a=new StringBuilder(),b=new StringBuilder();
    while(p<nums.length)
    {
        for(int i=1;i<nums.length;i++)
        if(nums[i]!=-1&&i!=max)
        {
            a.append(String.valueOf(nums[max]));
            b.append(String.valueOf(nums[i]));
            int k=0;
            while(true)
            {
                if(k==a.length()&&k==b.length()) break;
                if(k==a.length()) a.append(String.valueOf(nums[i]));
                if(k==b.length()) b.append(String.valueOf(nums[max]));
                if(a.charAt(k)==b.charAt(k)) 
                {
                    k++;
                    continue;
                }
                if(a.charAt(k)<b.charAt(k)) max=i;
                break;
            }
            a.delete(0,a.length());
            b.delete(0,b.length());
        }
        res.append(String.valueOf(nums[max]));
        nums[max]=-1;
        for(max=0;max<nums.length&&nums[max]==-1;max++);//找到一个未加入的元素下标
        p++;
    }
    return res.toString();
}

138.复制带随机指针的链表

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。且不能修改原链表。

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

  1. 先用O(n)时间构造新链表的value值和next指针。之后再用O( n 2 n^2 n2)时间连接新链表的random指针。方法是旧链表指针和新链表指针同步走旧链表指针到达旧链表中指向的random节点时,新链表此时指向的即为对应random节点

  2. 开辟一个O(n)大小的队列来保存旧链表的next指针,第一次构建新链表时,令新链表的random指针指向旧链表的random指针旧链表的next指针指向新链表中对应的节点。第二次遍历新链表令p.random=p.random.next;即可让新链表中的random指向对应的节点。之后再通过队列还原旧链表的next指针。时间复杂度为O(n)。在这里插入图片描述

  3. 方法2的问题在于恢复next指针时,一个链表恢复后另一个链表就恢复不了只能开辟空间保存。如果是同时恢复链表next指针的话就不需要另外开辟空间,方法是构建新链表时新节点插入旧链表中(插空),形成旧链表节点->新链表节点->旧链表节点的一个交错链表,新链表random指针指向旧链表对应位置节点的random指针。这样可以根据旧链表节点的next指针找到新链表中对应位置的节点。最后再遍历一次整个大链表把新旧链表分开。
    在这里插入图片描述

public Node copyRandomList(Node head) {
    if(head==null) return null;
    Node p=head,pne=p.next,copyhead=null; //copyhead新链表头
    while(pne!=null) //p旧链表节点。插入新节点
    {
        Node node=new Node(p.val);
        if(p==head) copyhead=node;
        p.next=node;
        node.next=pne;
        node.random=p.random;
        p=pne;
        pne=pne.next;
    }
    Node node=new Node(p.val);//插入最后一个
    node.random=p.random;
    node.next=null;
    p.next=node;
    p=copyhead=head.next; //防止原链表只有一个节点,copyhead为空情况
    while(p!=null) //找到新链表random节点
    {
        if(p.random!=null)
        p.random=p.random.next;
        p=p.next;
        p=p!=null?p.next:p;
    }
    p=copyhead;
    Node headnode=head;
    while(headnode!=null)  //新旧链表分开
    {
        headnode.next=p.next;
        if(p.next!=null)
        p.next=p.next.next;
        headnode=headnode.next;
        p=p.next;
    }
    return copyhead;
}

695.岛屿的最大面积

给你一个大小为 m x n 的二进制矩阵 grid 。岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。岛屿的面积是岛上值为 1 的单元格的数目。计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。

输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:6

  1. dfs。在原数组上标记访问位。

426.二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

输入:[4,2,5,1,3]

输出:[1,2,3,4,5]

  1. 一开始做法是想用线索二叉树的思路,把在左子树中的前驱找出来并指向当前节点,再出来进行一次遍历,把当前节点和在右子树的后继连起来。但后来改了几下发现很难实现,因为要找到后继关键是如何找到需要连接后继的节点
  • 在连接前驱时,如果仅仅修改前驱结点的right节点,那么向右遍历时,如果根据p.right.left!=p来判断是否是需要修改的节点的话,因为无法知道这个p.right是我们建立前驱添加的还是本来就有的,因此这个p.right.left可能在p的上面或者是下面,在上面的话需要修改的是p.right,在下面需要修改的是p。
  • 如果连接前驱时,把前驱节点的right节点和当前节点的left都修改的话,那么找到需要修改节点时,真正的后继节点是找不到的,因为前面修改left后相当于断链,并且真正的后继节点没有被其他节点所指向,导致无法根据右子树的根找到后继。
  1. dfs。这里比较难想的地方是用一个全局的pre节点来表示当前dfs搜索节点的前驱节点。中序遍历每次先搜索左子树,然后令当前节点为前驱节点(传给下面右子树),然后搜索右子树。每次搜索只连接当前节点和前驱节点,因为连接当前节点的后继和右子树连接其前驱是一样的,保证工作的平均分配。
 Node pre,head;
 public Node treeToDoublyList(Node root) {
     if(root==null) return root;
     dfs(root);
     while(root.left!=null) root=root.left;
     head=root;
     head.left=pre;
     pre.right=head;
     return head;
 }
 public void dfs(Node root)
 {
     if(root==null) return ;
     dfs(root.left);
     if(pre!=null)
     pre.right=root;
     root.left=pre;
     pre=root;
     dfs(root.right); 
 }

209.长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

  1. 双指针滑动窗口。右指针先向右移动大于等于target时,再让左指针右移缩小窗口直至小于target,此时两指针区间长度为一个最小子数组。

24.两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。

输入:head = [1,2,3,4]
输出:[2,1,4,3]

1.用三个节点进行交换和保存前驱。



今日总结

刷题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值