编程思想(技巧)---递归控制
来源:互联网 发布:诺查丹玛斯 知乎 编辑:程序博客网 时间:2024/06/07 23:58
最近在看谷歌面试官讲解的视频,特来分享一波~ 这个系列主要是讲编程思想(或者说技巧),主要包括:递归控制、循环控制、边界控制和一些数据结构的知识。这一节主要说下递归。
大佬们讲课很深奥,首先说了下数学归纳法,并用典型的求和的递推公式:首项加尾项乘以项数除以2,即n(n+1)/2讲解了数学归纳法,这也是递归思想的一部分理论基础。朋友们可以看看这些思想~ 下面说了递归的知识:
(1). 如何保证递归函数正确执行?
使用数学归纳法/自然语言,推纳出来之后转化为程序语言。
(2). 递归书写方法(套路)
- 严格定义递归函数作用,包括参数,返回值,side-effect
- 先一般,后特殊
- 每次调用必须缩小规模
- 每次问题规模缩小程度必须为1
根据上述套路我们就可以写出一个递归函数,下面举例说明:
例子1:链表创建,返回头节点,链表尾部指向null
描述:使用java创建链表。
ps:面试喜欢问链表是因为,链表容易理解但是代码难写。
下面java代码就用递归实现一个链表:
如图:
首先定义一个Node类,这个很好理解,每个Node包括节点值value,和下一个节点。
public class Node { private final int value; private Node next; public Node(int value){ this.value=value; this.next=null; } public int getValue() { return value; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } public static void printLinkedList(Node head){ while (head!=null){ System.out.print(head.getValue()); System.out.print(" "); head=head.getNext(); } System.out.println(); }}
下面使用递归思想实现链表创建:
public class LinkedListCreator { //1.严格定义递归函数作用,包括参数,返回值,side-effect /** * Creates a linked list. * @param data the data to create the list * @return head of the linked list. The returned linked list * ends with last node with getNext() == null. */ public static Node createLinkedList(List<Integer> data){ //2.先一般,后特殊。递归退出条件 if (data.isEmpty()){ return null; } Node firstNode = new Node(data.get(0)); //每次调用必须缩小规模,每次问题规模缩小程度为1 Node headOfSubList = createLinkedList(data.subList(1,data.size())); firstNode.setNext(headOfSubList); return firstNode; }}
链表的创建比较简单,使用递归几行代码就搞定了。下面看下链表反转的例子。
例子2:链表反转,将上述链表反转
描述:将一个链表反转。
实现如图:
主要思想也是使用递归,不断缩小反转的链表长度,最后把第一个元素指向null,并把每次递归的第一个元素的next节点指向第一个节点就ok了public class LinkedListReverse { /** * Reverses a linked list. * @param head the linked list to reverse * @return head of the reversed linked list */ public Node reverseLinkedList(Node head){ //size=0 or size=1 递归退出条件 if (head==null||head.getNext()==null){ return head; } //递归调用,每次都缩小规模 Node newHead = reverseLinkedList(head.getNext()); //把每次递归的第一个元素的next节点指向第一个节点 head.getNext().setNext(head); //第一个元素指向null head.setNext(null); return newHead; }}
递归反转使用递归也很容易理解啊!之前想破脑袋写了一大堆的代码还错了,使用递归确实代码异常简介,而且一目了然。
例子3:列出给定数列的所有组合
描述:给定一个任意长度的数列,求出该数列使用n个元素能组成的所有子集。
如图:第一个参数为数列的元素集合,第二个n为子集的长度。[1,2,3,4]中使用2个元素能组成的所有可能:
使用递归的实现思路如下:
combinations([1,2,3,4],2)
选1(即数组第0个元素)–>调用combinations([2,3,4],1)
不选1—>调用combinations([2,3,4],2)
代码实现:
/** * /** * Generates all combinations and output them, * selecting n elements from data. * @param data * @param n */ public static void combinations(List<Integer> selected, List<Integer> data,int n){ if (n==0){ //output all selected elements for (Integer i : selected){ System.out.print(i); System.out.println(" "); } System.out.println(); return; } if (data.isEmpty()){ return; } //select element 0 selected.add(data.get(0)); combinations(selected,data.subList(1,data.size()),n-1); //un-select element 0 selected.remove(selected.size()-1); combinations(selected,data.subList(1,data.size()),n); }}
使用递归的好处想必很明显了,代码简洁明了,方便理解,也方便编码,缺点就是stack的压力太大,效率很低,时间空间开销都很大。下一节使用循环解决这个问题~
以上递归算法小伙伴们可以自己调试,方便大家理解递归的运行过程
- 编程思想(技巧)---递归控制
- 编程思想(技巧)---循环控制
- 编程思想之递归
- 编程思想-访问权限控制
- 递归思想(一)
- (浅谈)递归思想
- 【Java编程思想--学习笔记(一)】访问控制-包
- 《JAVA编程思想》日志(四)------控制执行流程
- 《JAVA编程思想》日志(六)---------访问权限控制
- java编程思想学习笔记(4)--控制执行流程
- java编程思想---第四章(控制执行流程)
- 用递归的思想求和的编程
- 编程之递归思想理解记录
- Java编程算法基础---- 构造递归思想
- Java编程思想13.3-无意识的递归
- 编程技巧:lambda与递归
- C++抽象编程——递归简介(6)——相互递归与递归思想总结
- 【c++编程思想】第十章 名字控制
- ubuntu安装wdcp
- nginx 笔记
- 「OpenCV」conda安装一个OpenCV3
- HDU 6211 Pythagoras (勾股数+暴力枚举+优化)
- 2017 ACM/ICPC Asia Regional Qingdao Online
- 编程思想(技巧)---递归控制
- Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)
- puppet的rpm包安装及配置
- Maven构建多模块项目
- 按位与、或、异或等运算方法
- MySQL High Available with MHA(转)
- Spring JDBC-Spring事务管理之数据库事务基础知识
- [详解]优化API接口响应速度的套路
- Hiernate_day01