精华内容
下载资源
问答
  • public class SwapNode2 { public static ListNode swapNode(ListNode head){ if(head == null || head.next == null){ return head; } ListNode firstNode = head; ListNode secondNode = head.next;...
    public class SwapNode2 {
        public static ListNode swapNode(ListNode head){
            if(head == null || head.next == null){
                return head;
            }
            ListNode firstNode = head;
            ListNode secondNode = head.next;
    
            firstNode.next = swapNode(secondNode.next);
            secondNode.next = firstNode;
    
            return secondNode;
        }
    
        public static void main(String[] args){
            ListNode head = new ListNode(1);
            ListNode node1 = new ListNode(2);
            ListNode node2 = new ListNode(3);
            ListNode node3 = new ListNode(4);
            head.next = node1;
            node1.next = node2;
            node2.next = node3;
            head = swapNode(head);
            ListNode temp = head;
            while (temp != null){
                System.out.println(temp.val);
                temp = temp.next;
            }
        }
    }
    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    

     

    展开全文
  • 今天,我们来聊聊递归函数。为啥突然想到递归?其实就从电影名字《恐怖游轮》《盗梦空间》想到了。递归是啥?递归函数大家肯定写过,学校上课的时候,估计最开始的例子就是斐波拉契数列了吧。例如:intFibonacci(n){...

    今天,我们来聊聊递归函数。为啥突然想到递归?其实就从电影名字《恐怖游轮》《盗梦空间》想到了。

    9f5cd5e9a4b850d449becd46a9e6bc1f.png

    递归是啥?

    递归函数大家肯定写过,学校上课的时候,估计最开始的例子就是斐波拉契数列了吧。例如:

    int Fibonacci(n) {    if (n 

    递归函数简而言之就是在一个函数中,由“递归”调用自己。在写递归函数的时候,需要注意的地方就是递归函数的结束条件。用递归函数确实能简化很多算法的实现,比如常见的二叉树遍历等。但往往在写递归函数的时候,最容易出现的问题就是所谓的“栈溢出”。

    为什么会有“栈溢出”呢?因为函数调用的过程,都要借助“栈”这种存储结构来保存运行时的一些状态,比如函数调用过程中的变量拷贝,函数调用的地址等等。而“栈”往往存储空间是有限的,当超过其存储空间后,就会抛出著名的异常/错误“StackOverflowError”。

    我们以一个简单的加法为例,例如:

    int sum(int n) {    if (n <= 1) return n;    return n + sum(n-1);}std::cout << sum(100) <

    很简答,编译运行后,比较小的数字,能得到正确的答案,当数字扩大后,就会直接发生“segmentation fault”。

    尾递归又是啥?

    我得知这个概念,最开始还是因为很多年前一次面试,面试官问我“你知道什么是尾递归吗?”,我以为是“伪”递归,难道是假的递归???当初我也是懵逼状态(当初面试官忍住没笑也是厉害了

    )。从“尾”字可看出来即若函数在尾巴的地方递归调用自己。上面的例子写成尾递归,就变成了如下:

    int tailsum(int n, int sum) {    if (n == 0) return sum;    return tailsum(n-1, sum+n);}

    可以试试结果,计算从 1 加到 1000000,仍然是segmentation fault。为什么呢?因为这种写法,本质上还是有多层的函数嵌套调用,中间仍然有压栈、出栈等占用了存储空间(只不过能比前面的方法会省部分空间)。

    尾递归优化

    当你给编译选项开了优化之后,见证奇迹的时刻到了,居然能算出正确结果。如图所示:

    e15c55c94020db2f174029385fb46e08.png

    C++ 默认 segmentation fault, 开启编译优化后,能正常计算结果。

    原因就是因为编译器帮助做了尾递归优化,可以打开汇编代码看看(这里就不展示 C++的了)。后面我用大家比较熟悉的 JVM based 语言 Scala 来阐述这个优化过程。(好像 Java 的编译器没做这方面的优化,至少我实验我本地 JDK8 是没有的,不清楚最新版本的有木有)(scala 本身提供了一个注解帮助编译器强制校验是否能够进行尾递归优化@tailrec)

    object TailRecObject {   def tailSum(n: Int, sum: Int): Int = {        if (n == 0) return sum;        return tailSum(n-1, n+sum);   }   def main(args: Array[String]) {      println(tailSum(100, 0))      println(tailSum(1000000, 0))   }}

    结果如下图所示,默认情况下 scalac 做了尾递归优化,能够正确计算出结果,当通过 -g:notailcalls 编译参数去掉尾递归优化后,就发生了 Exception in thread "main" java.lang.StackOverflowError了。

    e5ba809fe7cf84689837dbfa5d1b279b.png

    默认启用尾递归优化正常计算结果,禁用尾递归优化则“StackOverflow”。

    我们来看看生成的字节码有什么不同。

    ab5a22f5162df0a55071f0a5ab7dff6b.png

    包含尾递归优化的字节码,直接 goto 循环。

    5234236aeeffd1bd02df3efe3ff7fe7f.png

    禁用尾递归优化的字节码,方法调用。

    从上面可以看出,尾递归优化后,变成循环了(前面的 C++ 类似)。

    好了,尾递归咱们就了解到这里。个人看法,我们知道有“尾递归”这个点就好了,有时候我们写递归就是为了方便,代码可读性好,如果确实是出于性能考虑,我们可以自己用迭代的方式去实现,不依赖于具体的编译器实现。当然对于像 scala 这样,有一些语法糖能够帮助校验和验证,也是一个不错的选择。但递归转迭代的能力,我们能具备岂不更好。

    作者: 程序猿石头

    原文链接:https://mp.weixin.qq.com/s/tccM3lwD2P8v6DTBVFVd4A

    展开全文
  • 保存 val1 的新值 递归 循环有一对「孪生兄弟」叫做递归。它们的作用都在于解决「重复」的事情。所不同的在于它们对于「重复」的部分的抽象描述不同 如果把要重复执行的指令放在一个「块」里面,称为循环体,并通过...

    d510d6f4aa624c300b1b664fb4e2bcc9.png

    不知不觉青铜三人行已经做了两个月的题了,这次轻松点,看看不一样的吧。

    机器擅长的事——重复

    作为专业的程序猿,经常被行业外的朋友问到,为什么要学习编程?其实,除了掌握技能提高工作效率、甚至成为职业以外。学习编程更重要的是:思维训练。

    其实,计算机从一开始就是为了帮助人们解决复杂问题而设计出来的。而在这个过程中,计算机程序的「思考」模型是一个叫“图灵机”的计算模型,图灵机是图灵 (Alan Mathison Turing) 祖师爷模拟人思考而发明出来的。为什么图灵祖师爷要发明图灵机呢?是因为他想要试图以自己和自己周围的天才科学家的思维方式作为人类的具体实例,来抽象总结出一套解决问题的办法。所以说,计算机程序的运作方式其实是一种人类尝试用简单的方式逐步去解决复杂问题的天才的思考方式。

    像机器一样思考 - ThoughtWorks洞见insights.thoughtworks.cn
    c350486668542df4df119a5873071d6e.png

    在如今的时代,计算机早已经充斥在我们生活的方方面面,想要更好地进行人机交互,或多或少地我们都需要一些「像机器一样」的思考方式。即使是作为专业程序员,不断培养自己像机器一样思考的思维模式也是必不可少的。

    既然要像机器一样去思考,那么不妨从计算机最擅长的事情——重复,开始说起吧。下面是来自 TED-Ed 中「Think like coder」系列课程的第一节,讲的就是计算机的重复——循环。

    3d8ceb62a4309d20f480db6ea081edb3.png
    From TED-Edhttps://www.zhihu.com/video/1250947428876394496

    各种编程语言的循环

    来看看在实际编程中,不同编程语言的循环写法有什么不同吧!

    for 循环

    • C
      int jj;
      for (jj=0; jj < 10; jj++) {
        printf("%d, ", jj);
      } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
    
      printf("n");
    • Java
    // For Loop
            // for loop structure => for(<start_statement>; <conditional>; <step>)
            for (int fooFor = 0; fooFor < 10; fooFor++) {
                System.out.println(fooFor);
                // Iterated 10 times, fooFor 0->9
            }
            System.out.println("fooFor Value: " + fooFor);
    • Javascript
    for (var i = 0; i < 5; i++){
        // will run 5 times
    }
    
    • Python
    for i in range(4):
        print(i)
    animals = ["dog", "cat", "mouse"]
    for i, value in enumerate(animals):
        print(i, value)
    • Rust
     // Ranges
        for i in 0u32..10 {
            print!("{} ", i);
        }
        println!("");
        // prints `0 1 2 3 4 5 6 7 8 9 `
    
    • Go
     for x := 0; x < 3; x++ { // ++ is a statement.
            fmt.Println("iteration", x)
      }
    
      for key, value := range map[string]int{"one": 1, "two": 2, "three": 3} {
            // for each pair in the map, print key and value
            fmt.Printf("key=%s, value=%dn", key, value)
        }
    

    while 循环

    • C
      int ii = 0;
      while (ii < 10) { //ANY value less than ten is true.
        printf("%d, ", ii++); // ii++ increments ii AFTER using its current value.
      } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
    
      printf("n");
    • Java
    int fooWhile = 0;
            while(fooWhile < 100) {
                System.out.println(fooWhile);
                // Increment the counter
                // Iterated 100 times, fooWhile 0,1,2...99
                fooWhile++;
            }
            System.out.println("fooWhile Value: " + fooWhile);
    • JavaScript
    // As does `while`.
    while (true){
        // An infinite loop!
    }
    
    • Python
    x = 0
    while x < 4:
        print(x)
        x += 1  # Shorthand for x = x + 1
    • Rust
     while 1 == 1 {
            println!("The universe is operating normally.");
            // break statement gets out of the while loop.
            //  It avoids useless iterations.
            break
        }
    
    • Go
    // Go 语言里面只有 for 循环,但是 for 循环可以不加范围
    
     for { // Infinite loop.
            break    // Just kidding.
            continue // Unreached.
        }
    

    循环的本质

    事实上,不管循环本身的写法和描述有什么改变,它的本质都是一种逻辑判断。也就是说,它们从根本上都是 until 循环的类型:

    当某条件满足的时候跳转到循环结束的地方,不然就跳转回循环开始的地方

    而基本所有的循环最后大概都会被编译成以下的样子,这叫做汇编语言,它是最接近计算机的思考方式的编程语言了。

            mov eax, val1        ; 把变量 val1 放到 EAX 里面
    beginwhile:
            cmp eax, val2        ; 比较 val1  val2
            jnl     endwhile     ; 如果 val1 不小于 val2,就跳到 endwhile 的地方
            inc    eax           ; val1++;
            dec    val2          ; val2--;
            jmp    beginwhile    ; 跳回到 beginwhile 的地方
    endwhile:
            mov    val1, eax     ;保存 val1 的新值

    递归

    循环有一对「孪生兄弟」叫做递归。它们的作用都在于解决「重复」的事情。所不同的在于它们对于「重复」的部分的抽象描述不同

    • 如果把要重复执行的指令放在一个「块」里面,称为循环体,并通过外部变量来调整每次循环执行的数据,就叫做循环。
    • 如果把要重复执行的指令抽象成「函数」,并通过传参数的形式来调整每次执行的数据,就称作递归啦!

    关于递归的详情可以看看来自 Helen 的视频讲解:

    青铜三人行——每周一题@递归讲解_哔哩哔哩 (゜-゜)つロ 干杯~-bilibiliwww.bilibili.com
    a841d0702f1fadf07e58ff3eaa16e2a4.png

    后面

    好啦,这次并没有做题,要讲的内容就这么多啦。有时候换换心情和视野也是很重要的,希望这次的内容可以当做故事看看,了解一些更多的事情。下次见啦!

    展开全文
  • 小米1面二分查找(递归和非递归)反转链表(递归和非递归)常用Java集合类HashMap为什么长度是2的n次幂,数据结构,扩容(包括元素移动的细节),线程不安全的问题ConcurrentHashMap怎么保证线程安全, 1.7和1 .8有什么变化,为...
    142c879a09c64e5aa2a673d9974572fe.png

    小米1面

    1. 二分查找(递归和非递归)
    2. 反转链表(递归和非递归)
    3. 常用Java集合类
    4. HashMap为什么长度是2的n次幂,数据结构,扩容(包括元素移动的细节),线程不安全的问题
    5. ConcurrentHashMap怎么保证线程安全, 1.7和1 .8有什么变化,为什么要要这么优化
    6. CopyOnWriteL ist怎么保证线程安全,为什么这么做
    7. Java synchronized关键字的作用,原理,锁升级、锁粗化、锁消除
    8. volatile关键字的作用原理
    9. MVCC
    10. 事务的ACID ,每- -项是如何保证的
    11. MySQL的索引|结构,为什么是B+树而不是B树
    12. .....

    小米2面

    1. 先升序后降序的数组排序
    2. 求递增数组中相加等于10的元素对
    3. 17^400 - 19100计算结果能不能被10整除
    4. 一个urI对应一-个random值,要求设计一 一个系统,根据ur|查询random值,具体到表怎么设计,索引怎么加,代码怎么写
    5. 讲项目, 画架构图,为什么这么设计,哪一块是你做的,为什么这么做,做了多久
    6. ....

    小米3面

    1. 自我介绍
    2. 镜像二叉树(递归和非递归)
    3. 删除二叉搜索树的某一个节点
    4. 给定数组,求第k大的数字
    5. 单例模式的几种写法,解释为什么
    6. tcp握手挥手过程,以及socket的状态变化
    7. 线程的状态,以及变化的时机
    8. Java内存模型,堆的组成, gc过程
    9. synchronized修饰同一个类的两个静态***同步吗,为什么
    10. 线程池设置了coreSize和maxSize之后,如果线程数量已经达到了coreSize ,这个时候进来-一个任务 ,会
    11. 怎么处理
    12. SQL查询优化怎么做
    13. 你的优点是什么,缺点是什么

    面完回去的路上,HR微信给了我口头offer,嗨心到哭 ~~

    现在看来,没过字节的面试还真是自己菜,哭了!!!上次还了分享一些我个人收集的面试资料,真的是有大用处,相信你如果能好好复习,也一定可以拿到想要的offer,这篇文章照例,如果你有需要,可以来找我获取到!

    所有的复习资料都是可以免费的分享给有需要的小伙伴们的!如果你需要的话可以转发文章后私信【面试资料】来免费获取到。

    01.Spring+Spring boot+SpringMVC 全面复习指南

    9bc8025872ecea1c0cd36c21760c42e3.png
    9f3ba52fa5cbd0c74d1b165ab5e9d7f9.png
    7e99087f462fc3f2dc8b584bc914c49a.png

    02.Dubbo+SpringCloud面试指南

    6aa2ea6bfcebeb78ed707742d4c3b8a0.png

    还有很多,都保存在WP里了,有需要的小伙伴可以私信我来获取到,因为是截图,所以图片会有些不清楚,文档不会有问题的,请大家伙放心!

    关注作者加转发文章后私信【面试资料】来免费获取到上述的文档资料哦!

    展开全文
  • 由于各种需要有个需求,要使用Java递归实现; 现有Java List数据集合一个,里面的数据结构如下: id name partid ------------------------------- 1 A null 2 a1 1 3 a11 2 4 a111 3 5 a2 ...
  • /* 上面得到的chidrenList仅仅是底下一层的节点集合,也就是说只包含了子节点,未包含子节点下的所有子孙节点 如果变量pid表示第一层的话,这里我们从第二层开始递归 也就是不停的寻找下一层下一层下一层……直到不...
  • /* 上面得到的chidrenList仅仅是底下一层的节点集合,也就是说只包含了子节点,未包含子节点下的所有子孙节点 如果变量pid表示第一层的话,这里我们从第二层开始递归 也就是不停的寻找下一层下一层下一层……直到不...
  • java递归写法

    千次阅读 2017-06-16 05:59:53
    递归是自己调用自己,java里的递归写法如下: /**  * 1*2*(n-1)*n的计算形式,使用递归实现  * @author Administrator  *  */ public class DiGui { //初始化变量,不能使用默认值 private static long ...
  • package 快排; import java.util.Arrays; import java.util.Random; import java.util.Stack; ...//时间复杂度:最坏情况O(N^2) 对一个降序的数组,用快排进行升序排序 ... //快速排序递归写法 public static void sort
  • 斐波拉契数列的递归和非递归写法(c/java
  • Java 基本的递归写法

    千次阅读 2016-03-11 14:55:54
    //用于递归的方法,只有把 id 下的所有子孙节点全部存入idList,才会进行下一轮循环 getChildrens(map, id ,idList); } //将之前第一层子节点也加入进来(这个地方根据需要来) idList.addAll...
  • 递归写法

    2020-10-18 11:50:44
    递归的写法,一开始就是递归的终止条件,然后处理当前的层,然后再下转。 那么处理当前层的话就是相当于访问了结点 node,然后把这个结点 node 加到已访问的结点里面去; 那么终止条件的话,就是...//递归写法...
  • 经典的Fibonacci数的问题 主要想展示一下迭代与递归,以及尾递归的三种写法,以及他们各自的时间性能。 public class Fibonacci { /*迭代*/ public static int process_loop(int n) { ...
  • java poi读取excel这种层级结构的递归写法,思路:同列的循环获取,子级递归获取,想清楚每一个单元格变化的地方,传不同的参数。exel的单元格的值只能先读取行,再获取列。 包括合并单元格的获取并不是有序的,...
  • package 归并排序; //时间复杂度 O(NLogN) //空间复杂度 O(N + LogN) = O(N) //稳定排序 //归并排序可以高效对链表进行排序 //数组可以进行随机访问,链表只能取...import java.util.Arrays; public class Test {
  • 递归和优化快速排序非递归优化1、 优化基准值的选择2、减少递归次数3、结合堆排序 快速排序 非递归 本质上需要用非递归模拟递归,借助一个栈 import java.util.Arrays; import java.util.Stack; public class ...
  • 先序遍历 从根节点来看,遍历顺序是根 -&gt; 左 -&gt; 右 我们用一个栈来储存二叉树中的节点值,访问一个节点时,先打印这个节点,再将这个节点的左子树和右子树放进栈中,先拿出左子树即可 ...
  • import java.util.Scanner; public class 棋盘覆盖问题{ // 定义棋盘的大小:2^k,需要的骨牌数是:(4^k-1)/3 private static int BOARD_SIZE = 8; // 定义一个二维数组用来模拟棋盘 private static int[][] ...
  • 下面我们来探讨一下快速排序的递归写法思想吧。设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它左边,所有比它大的数都放到它右边,这个...
  • 递归程序: class TreeNode{ TreeNode left; TreeNode right; int data; } public class Tree1 { public static void Exchange(TreeNode head){ if(null==head||(head.left==null&&head.right==null)){ ...
  • 下面我们来探讨一下快速排序的递归写法思想吧。 设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它左边,所有比它大的数都放到它右边...
  • 二叉树的遍历方式分为:深度优先遍历 和 广度优先遍历。其中,深度优先遍历又分为:...今天,给大家带来深度优先遍历的递归写法: 前序遍历 public static void preOrder(Node root){ if(root == null){ return...
  • 我们发现中都是一些条件只有满足这些条件了才...课前准备 云课堂APP 班级二维码 前情回顾 方法的嵌套调用 1方法嵌套调用的写法 2方法嵌套程序的流程执行 教学目标的确定 通过汉诺塔小游戏程序了解java递归的编程思想和
  • 二叉树前序中序后序遍历的递归遍历非常简单,这里就写一下非递归的方法。 核心思路是把每一个结点看成父节点,叶子结点是左右孩子是null的父结点。 前序遍历 思路: 使用一个栈来存储结点,以便回到之前的父结点...
  • 简单的递归写法

    千次阅读 2019-09-19 11:11:54
    递归:说白了就是方法之中在调用自己的方法 ...import java.io.File; //递归 自己调用自己 public class Digui { //获取E盘下新建文件夹中的所有文件 public static void showAllFile(File fil...
  • java递归

    2019-04-21 19:41:03
    递归写法不同,效率不同 public class RecursionMain { private static long time = 0L; public static void main(String[] args) { time = System.nanoTime(); System.out.println(RecursionTest....

空空如也

空空如也

1 2 3 4 5 ... 14
收藏数 270
精华内容 108
关键字:

java递归写法

java 订阅