剑指offer全集系列(1)

目录

JZ3 数组中重复的数字

JZ4 二维数组中的查找

JZ5 替换空格

JZ6 从尾到头打印链表

JZ18 删除链表的节点

JZ22 链表中倒数最后k个结点


题目为剑指offer top100题目, 欢迎大家来学习😘


JZ3 数组中重复的数字

数组中重复的数字_牛客题霸_牛客网在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道。题目来自【牛客题霸】https://www.nowcoder.com/practice/6fe361ede7e54db1b84adc81d09d8524?tpId=265&tqId=39207&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D13&difficulty=undefined&judgeStatus=undefined&tags=&title=

 解法1: 暴力循环

        也就是说, 直接开始从最左边的2开始遍历整个数组, 如果发现有重复的, 就直接返回这个数字, 如果没有重复的, 就选中下一个数字3, 然后开始遍历整个数组. 以此类推, 如果一直到数组最后一个数都没有重复的话就返回-1, 否则返回重复的数.

        此方法没有使用额外的空间, 所以空间复杂度为O(1)
        此方法经历了两层for循环, 每次循环的长度都为数组的长度n, 因此时间复杂度为O(n^2)

import java.util.*;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * @param numbers int整型一维数组 
     * @return int整型
     */
    public int duplicate (int[] numbers) {
        for(int i = 0; i < numbers.length; i++) {
            int tem = numbers[i];
            for(int j = i + 1; j < numbers.length; j ++) {
                if (tem == numbers[j]) {
                    return tem;
                }
            }
        }
        return -1;
    }
}

 解法2: 集合Set

        创建一个集合对象, 从0下标开始遍历数组, 每次遍历的时候, 看这个数是否在集合中已经存在, 如果不存在就将这个数添加到集合当中, 如果这个数在集合中已经存在, 就直接返回这个数. 如果遍历完整个数组的时候, 还没有在集合中找到重复的数, 那么就返回-1.

        此方法创建了一个集合, 最坏的情况下需要存储数组里面所有的元素, 因此空间复杂度为O(n)
        此方法只需要遍历一次数组即可, 因此时间复杂度为O(n)

import java.util.*;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * @param numbers int整型一维数组 
     * @return int整型
     */
    public int duplicate (int[] numbers) {
        Set<Integer> set = new TreeSet<>();
        for(int i = 0; i < numbers.length; i++) {
            int tem = numbers[i];
            if (set.contains(tem)) {
                return tem;
            }
            set.add(tem);
        }
        return -1;
    }
}

解法3 : 排序和遍历

        根据题目所给的数组的长度为n, 然后这个数组里面的数的取值范围又是[0, n - 1], 也就是说, 如果这个数组里面没有重复的, 那么将这个数组从小到大排序之后, 如果不存在重复的, 那么数组里面的元素大小就应该和它的下标相等, 如果不等, 则说明存在重复的.

        此方法没有使用额外的空间, 因此空间复杂度为O(1)
        此方法需要遍历一次集合或者是排序时间复杂度为O(n)

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型一维数组 
     * @return int整型
     */
    public int duplicate (int[] numbers) {
        if (numbers.length == 0) {
            return -1;
        }
        Arrays.sort((numbers));
        int dele = numbers[0];
        for(int i = 0; i < numbers.length; i++) {
            if ((i + dele) != numbers[i]) {
                return numbers[i];
            }
        }
        return -1;
    }
}


JZ4 二维数组中的查找

二维数组中的查找_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=265&tqId=39208&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D13&difficulty=undefined&judgeStatus=undefined&tags=&title=

 

 解法1 : 暴力搜索

        一个很简单的方法, 就是, 把里面所有的元素全部都遍历一次, 查找里面是否存在target这个元素, 如果不存在那么就返回false, 如果存在就返回true. 

        由于没有用到额外的空间, 所以空间复杂度为O(1)
        需要遍历整个二维数组, 所以空间复杂度为O(n * m)

此外,对于每一行, 我们除了直接从左到右进行搜索, 还可以进行二分查找, 因为每一行都是有序的.
使用二分查找:
        时间复杂度:O(Mlog N )  时间复杂度将进一步缩小
        空间复杂度:O(1)

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param target int整型 
     * @param array int整型二维数组 
     * @return bool布尔型
     */
    public boolean Find (int target, int[][] array) {
        for(int i = 0; i < array.length; i++) {
            for(int j = 0; j < array[0].length; j++) {
                if (target == array[i][j]) {
                    return true;
                }
            }
        }
        return false;
    }
}

 解法2 : 线性搜索

         建立如图的坐标系, target放在左下角进行搜索, 如图, 假设现在target为7, 从左下角第一个元素6开始比较, target比6大, 往右一个元素继续比较, 也就是继续和8比较, 现在target = 7 比8小, 所以往上一个元素, 也就是和7进行比较, target = 7, 于是返回true.  假设target为3, 根据上图搜索, 依次比较的元素为: 6 -> 4 -> 2 -> 4 -> 2 -> 8, 比较完后, 最后遇到比较的元素的下标出了数组的边界, 也就是变成了-1的时候, 就结束比较.

  • 时间复杂度:O(m+n),遍历矩阵的时候,最多经过矩阵的一行一列
  • 空间复杂度:O(1),常数级变量,无额外辅助空间
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param target int整型 
     * @param array int整型二维数组 
     * @return bool布尔型
     */
    public boolean Find (int target, int[][] array) {
        if (array[0].length == 0) {
            return false;
        }
        // 空间复杂度o(1), 时间复杂度O(m + n)
        int x = 0;
        int y = array.length - 1;
        while (x != array[0].length && y != -1) {
            int now = array[y][x];
            if (target > now) {
                x++;
            } else if (target < now) {
                y--;
            } else {
                return true;
            }
        }
        return false;
    }
}


JZ5 替换空格

替换空格_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/0e26e5551f2b489b9f58bc83aa4b6c68?tpId=265&tqId=39209&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D13&difficulty=undefined&judgeStatus=undefined&tags=&title=

        依次遍历字符串, 从字符串的第一个字符开始, 然后新建一个StringBuilder  sb, 如果遍历的字符不是空格则直接将其添加到sb中, 如果是空格, 就添加 %20 到sb中去. 然后返回sb.toString();

  • 时间复杂度O(n)
  • 空间复杂度O(n)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param s string字符串 
     * @return string字符串
     */
    public String replaceSpace (String s) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == ' ') {
                sb.append("%20");
            } else {
                sb.append(s.charAt(i));
            }
        }
        return sb.toString();
    }
}


JZ6 从尾到头打印链表

从尾到头打印链表_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035?tpId=265&tqId=39210&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D13&difficulty=undefined&judgeStatus=undefined&tags=&title= 

方法一: 使用数组来记录链表里面所有的元素, 然后新建一个链表, 将数组里面的元素反向添加到新建的链表中去.

  • 空间复杂度为O(n)
  • 时间复杂度为O(n)
import java.util.*;
/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        int[] arr = new int[10000];
        int size = 0;
        ListNode tem = listNode;
        while (tem != null) {
            arr[size++] = tem.val;
            tem = tem.next;
        }
        ArrayList<Integer> list = new ArrayList<>();
        for(int i = size - 1; i >= 0; i--) {
            list.add(arr[i]);
        }
        return list;
    }
}

 方法二: 使用堆栈, 其实总体上的思想其实和方法一差不多的, 只是换了一个形式.

  • 时间复杂度为O(n)
  • 空间复杂度为O(n)
import java.util.*;
/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        Stack<Integer> stack = new Stack<>();
        ListNode tem = listNode;
        while (tem != null) {
            stack.push(tem.val);
            tem = tem.next;
        }
        ArrayList<Integer> list = new ArrayList<>();
        while (!stack.isEmpty()) {
            int topElement = stack.pop();
            list.add(topElement);
        }
        return list;
    }
}

方法三: 递归, 既然我们正向不能直接得出结果, 那我们就可以使用递归, 先将标记结点递归到最后一位, 然后从最后一位开始反方向遍历元素:

  • 时间复杂度为O(n) 
  • 空间复杂度为O(n)
import java.util.*;
/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> list = new ArrayList<>();
        function(list, listNode);
        return list;
    }

    public static void function(ArrayList<Integer> list, ListNode node) {
        if (node == null) {
            return;
        }
        function(list, node.next);
        list.add(node.val);
    }
}


JZ18 删除链表的节点

删除链表的节点_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/f9f78ca89ad643c99701a7142bd59f5d?tpId=265&tqId=39280&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D13&difficulty=undefined&judgeStatus=undefined&tags=&title= 

        这题比较简单, 我们直接使用遍历 然后删除结点即可, 也就是使用双指针的形式, 一个指针用来记录后面的结点, 方式丢失, 一个指针用来连接记录结点. 但是要注意空指针的问题. 以及元素比较少的时候该怎么判断.

  • 时间复杂度O(n)
  • 空间复杂度O(1)
import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @param val int整型 
     * @return ListNode类
     */
    public ListNode deleteNode (ListNode head, int val) {
        ListNode l = head;
        ListNode r = head.next;
        if (l.val == val) {
            return head.next;
        }
        while (r != null) {
            if (r.val == val) {
                l.next = r.next;
                break;
            }
            r = r.next;
            l = l.next;
        }
        return head;
    }
}


JZ22 链表中倒数最后k个结点

链表中倒数最后k个结点_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/886370fe658f41b498d40fb34ae76ff9?tpId=265&tqId=39224&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D13&difficulty=undefined&judgeStatus=undefined&tags=&title= 

方法一: 直接遍历, 利用性质, 先遍历出链表里面所有的元素的总个数, 然后再计算出需要走的步数, 

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pHead ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    public ListNode FindKthToTail (ListNode pHead, int k) {
        int size = 0;
        ListNode tem = pHead;
        while (tem != null) {
            size ++;
            tem = tem.next;
        }
        if (size < k) {
            return null;
        }
        for(int i = 0; i < size - k; i++) {
            pHead = pHead.next;
        }
        return pHead;
    }
}

 方法二: 快慢指针, 一个快一个慢:

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pHead ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    public ListNode FindKthToTail (ListNode pHead, int k) {
        ListNode slow = pHead;
        ListNode fast = pHead;
        if (slow == null) {
            return null;
        }
        for(int i = 0; i < k; i++) {
            fast = fast.next;
            if (i != k - 1 && fast == null) {
                return null;
            }
        }
        while (fast != null) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}

方法三 : 使用堆栈, 将所有的结点, 从pHead开始, 全部压入栈中, 然后取出第k个结点, 就是倒数第k个结点了:

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pHead ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    public ListNode FindKthToTail (ListNode pHead, int k) {
        // write code here
        Stack<ListNode> stack = new Stack<>();
        while (pHead != null) {
            stack.push(pHead);
            pHead = pHead.next;
        }
        if (stack.isEmpty()) {
            return null;
        }
        ListNode result = null;
        for(int i = 0; i < k; i++) {
            result = stack.pop();
            if (i != k - 1 && stack.isEmpty()) {
                return null;
            }
        }
        return result;
    }
}




剑指offer 的图像结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/82372.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】传输层协议:UDP和TCP

争做西格玛男人 文章目录 一、UDP协议1.端口号2.理解UDP报头3.UDP的特点&#xff08;面向数据报&#xff0c;全双工&#xff09; 二、TCP协议1.理解TCP报头某些TCP的策略1.1 TCP报头字段&#xff08;TCP的黏包问题&#xff09;1.2 网络协议栈和linux系统的联系&#xff08;以p…

配置使用Gitee账号认证登录Grafana

三方社会化身份源 集成gitee第三方登录 第三方登录的原理 所谓第三方登录&#xff0c;实质就是 OAuth 授权。用户想要登录 A 网站&#xff0c;A 网站让用户提供第三方网站的数据&#xff0c;证明自己的身份。获取第三方网站的身份数据&#xff0c;就需要 OAuth 授权。 举例来…

verilog学习笔记6——锁存器和触发器

文章目录 前言一、锁存器1、基本SR锁存器——或非门实现2、基本SR锁存器——与非门实现3、门控SR锁存器4、门控D锁存器 二、触发器1、 电平触发的RS触发器/同步SR触发器2、电平触发的D触发器/D型锁存器3、边沿触发的D触发器4、脉冲触发的RS触发器 三、边沿触发、脉冲触发、电平…

攻防世界-fileinclude

原题 解题思路 题目已经告诉了&#xff0c;flag在flag.php中&#xff0c;先查看网页源代码&#xff08;快捷键CTRLU&#xff09;。 通过抓包修改&#xff0c;可以把lan变量赋值flag。在cookie处修改。新打开的网页没有cookie&#xff0c;直接添加“Cookie: languagephp://filte…

PCAP01介绍和STM32模拟SPI驱动

一.芯片介绍 Pcap01是德国acam公司设计的一款革命性的电容测量芯片。该芯片 内部有DSP计算单元&#xff0c;可以直接将电容元件接到Pcap01芯片&#xff0c;然后芯片计算出容值大小&#xff0c;通过SPI总线将电容容值数据传送给CPU&#xff0c;电容测量完全数字化。 二,测量原…

excel常见的数学函数篇2

一、数学函数 1、ABS(number)&#xff1a;返回数字的绝对值 语法&#xff1a;ABS(数字)&#xff1b;返回数字的绝对值&#xff1b;若引用单元格&#xff0c;把数字换为单元格地址即可 2、INT(number)&#xff1a;向小取整 语法&#xff1a;INT(数字)&#xff1b;若引用单元格…

QT SSL handshake failed问题分析与解决 QT基础入门【网络编程】openssl

问题: 使用https方式进行post 和get请求时,有时候会出现SSL handshake failed的问题,其实是调用Qt QNetworkAccessManager出现的问题。 其实SSL握手是建立HTTPS连接过程的第一步。为了验证和建立连接,用户的浏览器和网站的服务器必须经过一系列检查(握手),从而建立HTTP…

【STM32RT-Thread零基础入门】 4. 线程介绍(理论)

文章目录 前言一、线程的概念二、线程的调度三、上下文切换四、线程的重要属性1. 线程栈2. 线程的状态3. 线程优先级4. 线程时间片5. 线程的入口函数 五、RT-Thread命令查看系统线程信息总结 前言 前文中的最后一个任务发现&#xff0c;一个main()函数很难同时实现按键功能和闪…

postgresql的在windows下的安装

postgresql的在windows下的安装 下载安装步骤超级用户设置密码本地化设置安装信息安装完成 查看postgresql服务pgAdmin的使用打开命令 行工具查询数据库版本 创建数据库 下载 官网地址 https://www.postgresql.org/ 下载页面 https://www.postgresql.org/download/ windows下…

使用yolov5进行安全帽检测填坑指南

参考项目 c​​​​​​​​​​​​​​GitHub - PeterH0323/Smart_Construction: Base on YOLOv5 Head Person Helmet Detection on Construction Sites&#xff0c;基于目标检测工地安全帽和禁入危险区域识别系统&#xff0c;&#x1f680;&#x1f606;附 YOLOv5 训练自己的…

小素数,大智慧

小素数&#xff0c;大智慧 定义判断方法方法1方法2方法3方法4方法5方法6方法7 定义 素数&#xff08;质数&#xff09;&#xff1a;在大于 1 的自然数中&#xff0c;只有 1 和该数本身两个因数的数 素数&#xff08;质数&#xff09;&#xff1a;在大于1的自然数中&#xff0c;…

ES6自用笔记

目录 原型链 引用类型&#xff1a;__proto__(隐式原型)属性&#xff0c;属性值是对象函数&#xff1a;prototype(原型)属性&#xff0c;属性值是对象 相关方法 person.prototype.isPrototypeOf(stu) Object.getPrototypeOf(Object)替换已不推荐的Object._ _ proto _ _ Ob…

易服客工作室:Uncode主题 - 创意和WooCommerce WordPress主题

Uncode主题是一款像素完美的创意 WordPress 主题&#xff0c;适用于任何类型的网站&#xff08;作品集、代理机构、自由职业者、博客&#xff09;&#xff0c;也是适用于商店&#xff08;电子商务、在线商店、企业&#xff09;的顶级 WooCommerce 主题。Uncode 的设计非常注重细…

21.1 CSS 文字样式

1. 字体倾斜 font-style属性: 为文本设置字体样式.常用取值: normal: 正常显示文本. 快捷键: fstab. italic: 显示斜体文本. 快捷键: fsntab.<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>fo…

matlab中exp和expm的区别

exp()为数组 X 中的每个元素返回指数 e x e^{x} ex expm()计算 X 的矩阵指数。 两个函数传入矩阵后计算的结果是不同的&#xff0c;千万不能混淆。之前曾经想当然得把exp里传入矩阵当矩阵指数使用&#xff0c;也未验证正确性&#xff0c;实不应该。

深入理解 Flutter 图片加载原理 | 京东云技术团队

前言 随着Flutter稳定版本逐步迭代更新&#xff0c;京东APP内部的Flutter业务也日益增多&#xff0c;Flutter开发为我们提供了高效的开发环境、优秀的跨平台适配、丰富的功能组件及动画、接近原生的交互体验&#xff0c;但随之也带来了一些OOM问题&#xff0c;通过线上监控信息…

【leetcode 力扣刷题】快乐数/可被k整除的最小整数(可能存在无限循环的技巧题)

可能存在无限循环的技巧题 202. 快乐数数学分析 1015. 可被k整除的最小整数数学分析 202. 快乐数 题目链接&#xff1a;202. 快乐数 题目内容&#xff1a; 理解题意&#xff0c;快乐数就是重复每位数的平方之和得到的新数的过程&#xff0c;最终这个数能变成1。变成1以后&…

docker的资源控制及数据管理

docker的资源控制及docker数据管理 一.docker的资源控制 1.CPU 资源控制 1.1 资源控制工具 cgroups&#xff0c;是一个非常强大的linux内核工具&#xff0c;他不仅可以限制被 namespace 隔离起来的资源&#xff0c; 还可以为资源设置权重、计算使用量、操控进程启停等等。 …

HTML中的字符串转义

为什么要转义&#xff1f; 转义可以防止 xss 攻击。接下来&#xff0c;我们来看一下如何转义。 HTML Sanitizer API Sanitizer 是浏览器自带的转义方法&#xff0c;在2021年初被提出&#xff0c;兼容性问题很大。 列举几个常用的 API&#xff1a; const $div document.qu…

Python批量爬虫下载文件——把Excel中的超链接快速变成网址

本文的背景是&#xff1a;大学关系很好的老师问我能不能把Excel中1000个超链接网址对应的pdf文档下载下来。虽然可以手动一个一个点击下载&#xff0c;但是这样太费人力和时间了。我想起了之前的爬虫经验&#xff0c;给老师分析了一下可行性&#xff0c;就动手实践了。    没…