套路算法--算法碎块(第一弹)

本文精选了一系列实用的算法碎块,包括寻找数组的最大最小值、最大公约数递归求解、链表翻转、约瑟夫环计算公式及二叉树的遍历与序列化等。旨在帮助读者在算法学习过程中积累基础工具。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

各种繁杂,但总是容易忽视,优秀的代码碎块。

优秀的算法总是让人惊艳,到底是何种大牛,何等想法,竟然能实现了如此的数字或是字符处理,更是能实现了那种总是正常,但是仔细想来却是匪夷所思的目的。

但是往往优秀的算法的根基,有一些则是是算法碎块的堆砌,在真正踏上了算法学习的道路上,我们还需要准备些真正的有用,实在的工具。

而不让我们在追求算法的道路上,遭遇拦路虎,而无工具,只能赤手空拳,绞尽脑汁去硬拼,那可不安全咯。

为此,特地做一部分的算法碎块整理,以便能在记忆过后,能对应相应的算法想到了解决方法,从而一块块的处理得到完整完好的解答。

本文涉及内容:
1.寻找数组中的最大最小值
2.寻找最大公约数的递归函数(一行搞定)
3.翻转单向链表
4.翻转双向链表
5.约瑟夫环计算公式(递归版本)
6.非递归的二叉树前序遍历
7.非递归的二叉树中序遍历
8.非递归的二叉树后序遍历
9.二叉树的序列化(使用前序)
10.二叉树的反序列化(使用前序)

 代码块一 --寻找数组中的最大最小值

int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i = 0 ;i < arr.length ; i++) {
    max = Math.max(max, arr[i]);
    min = Math.min(min, arr[i]);
}

代码块二 -- 寻找最大公约数的递归函数(一行搞定)

public static int gcd(int m ,int n) {
    return n==0 ? m : gcd(n, m%n);
}
//gcd : greatest common divisor 最大公约数

代码块三 --反转单向链表 

        public class Node {
		public int value;
		public Node next ;
		
		public Node(int value) {
			this.value = value;
		}
	}
	
	public Node reverList(Node head) {
		Node pre = null;
		Node next = null;
		while (head != null) {
			next = head.next;
			head.next = pre;
			pre = head;
			head = next;
		}
		return pre;
	}

代码块四 -- 翻转双向链表 

        public class DoubleNode {
		public int value;
		public DoubleNode last ;//指向前节点的指针
		public DoubleNode next;//指向下(后)节点的指针
		public DoubleNode(int value) {
			this.value = value;
		}
	}
	
	public static DoubleNode reverseDoubleList(DoubleNode head) {
		DoubleNode pre = null;
		DoubleNode next = null;
		while(head != null) {
			next = head.next;
			head.next = pre;
			head.last = next;//对比单向链表反转,只差在这个位置
			pre = head;
			head = next;
		}
		return pre;
	}

代码块五 --约瑟夫环计算公式(递归)

数学公式推导:f(n)=(f(n-1)-1+m)%n+1

        如果n个人编号从0编到n-1,那么f(n)=(f(n-1)+m)%n成立,如果换算成1到n编号,f(n)-1=((f(n-1)-1)+m)%n,也就是f(n)=((f(n-1)-1)+m)%n+1

       另外可知道,当n=2时,m为奇数时最后留下的是2,m为偶数时最后留下的是1。

        //找到n个人时,出队的编号(递归)
	public static int getLive(int n, int m) {
		//只有一个节点,返回位置就是1
		if (n == 1) {
			return 1;
		}
		return (getLive(n-1, m)+m-1)% n + 1;
	}

代码块六 -- 非递归的二叉树前序遍历

非递归的二叉树前序遍历,具体流程为:
1.申请一个新栈,记为stack。然后就将头结点root 压入栈中。
2.从stack栈中弹出,记为cur,然后打印cur节点值,再将cur的右孩子压入栈中(如果不为空的话),再将cur 的左孩子压入栈中(如果不为空的话)。
不断重复2的过程,直到栈为空为止。
       public static void traverseTreePreOrder(Node root) {
		if (root != null) {
			Stack<Node> stack = new Stack<>();
			stack.push(root);
			while( !stack.isEmpty()) {
				root = stack.pop();
				System.out.println(root.value + " ");
				if (root.right !=null) {
					stack.push(root.right);
				}
				if (root.left !=null) {
					stack.push(root.left);
				}
			}
		}
		System.out.println();
	}

代码块七 -- 非递归的二叉树后序遍历

因为前序和后序遍历的非递归实现,有着异曲同工之妙,并且相差所在,只在于压入栈的左右孩子的顺序而已。
具体过程如下:
1.申请两个栈,一个s1,一个s2,用于将头结点root压入s1栈中。
2.从s1栈中弹出的节点记为cur,然后依次将cur的左孩子和右孩子压入栈s1中。
3.在以上弹出的过程中,从s1栈中弹出的节点都放到s2中。
4.重复1,2,3的过程,直到了s1栈为空位置。
最后,将s2中的所有节点弹出打印,即为后续遍历。
        public static void traverseTreePosOrder(Node root) {
		if (root != null) {
			Stack<Node> stack1 = new Stack<>();
			Stack<Node> stack2 = new Stack<>();
			stack1.push(root);
			while( !stack1.isEmpty()) {
				root = stack1.pop();
				stack2.push(root);
				if (root.left !=null) {
					stack1.push(root.left);
				}
				if (root.right !=null) {
					stack1.push(root.right);
				}
			}
			while (!stack2.isEmpty()) {
				System.out.println(stack2.pop().value + " ");
			}
		}
		System.out.println();
	}

代码块八 -- 非递归二叉树中序遍历

非递归二叉树中序遍历,具体过程如下:
1.申请一个新栈stack。初始化,令变量cur = head。
2.先将头结点root(cur),压入stack中。对于root(cur)为头节点的整颗子树,依次将它的左边界压入栈中,也即,不断令cur = cur .left。不断重复2.
3.直到root==null,则从栈中弹出一个节点,记为node,打印node值,此时cur= cur.right,然后继续重复2.
当stack为空,且cur为空时,整个遍历过程停止。
       public static void traverseTreeInOrder(Node root) {
		if (root != null) {
			Stack<Node> stack = new Stack<>();
			while( !stack.isEmpty() || root != null) {
				if (root !=null) {
					stack.push(root);
					root = root.left;
				}else {
					root = stack.pop();
					System.out.println(root.value + " ");
					root = root.right;
				}
			}
		}
		System.out.println();
	}

代码块九 -- 二叉树的序列化

何为序列化?
二叉树被记录成文件的过程就是叫做二叉树的序列化。太字面了,还是不懂,那么这样解释,我们将二叉树给做成了一个字符串或者是数组来保存起来,这个数组可以唯一的表示成某一颗二叉树。在需要的时候,能对其进行相应的操作,犹如在操作二叉树本身一样,之前的过程就是叫做二叉树的序列化。
        //二叉树结构定义
        public class Node{
		public int value;
		public Node left;
		public Node right;
		public Node(int value) {
			this.value = value;
		}
	}

	//序列化过程
	public String preSerializable(Node head) {
		//"#"表示值为空,"!"表示该值结束(亦可换成其他同样代表的字符均可)
		if (head == null) {
			return "#!";
		}
		String result = head.value+"";
		result+= preSerializable(head.left);
		result+=preSerializable(head.right);
		return result;
	}

代码块十 -- 二叉树的反序列化

序列化二叉树只是为了方便我们保存二叉树的原有结构或者说是有其他的需求。而反序列化就是在得到了序列化二叉树结果之后,反过来生成原有的二叉树。
       //二叉树结构定义
        public class Node{
		public int value;
		public Node left;
		public Node right;
		public Node(int value) {
			this.value = value;
		}
	}
       public String preSerializable(Node head) {
		//"#"表示值为空,"!"表示该值结束(亦可换成其他同样代表的字符均可)
		if (head == null) {
			return "#!";
		}
		String result = head.value+"";
		result+= preSerializable(head.left);
		result+=preSerializable(head.right);
		return result;
	}
	
	public Node recoverByPreSerializable(String result) {
		String[] nodes = result.split("!");
		Queue<String> queue = new LinkedList<String>();
		for(int i = 0 ;i < nodes.length; i++) {
			queue.offer(nodes[i]);
		}
		return recoverByPreOrder(queue);
	}

未完待续哦~!(*❦ω❦)后续将继续更新总结~

本文为博主原创总结更新,谢绝转载,本文博客地址为:https://blog.youkuaiyun.com/mukvintt/article/details/81537158

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值