【数据结构-算法】:数据结构和算法的一些个人总结(Java实现)
文章目录
数据结构的分类
冒泡排序
选择排序
删除链表中的节点
反转链表
移除链表元素
递归实现两两交换链表中的节点
杨辉三角
移除元素
移动零
判断子序列
二叉树的最大深度
平衡二叉树
两个数组的交集
重建二叉树
样例
有关(大小)堆的一些随笔
魔术索引
二叉树的镜像
对称的二叉树
二叉树的层序遍历
二叉树的中序遍历
二叉树的后序遍历
二叉树的前序遍历
二叉树的最近公共祖先
二叉树的深度
飞地的数量
岛屿数量
将有序数组转化为二叉搜索树
判断二分图
N叉树的层序遍历
N叉树的后序遍历
N叉树的前序遍历
相同的树
第一个只出现一次的字符
红黑树性质
罗马数字转整数
数据结构的分类
线性结构:动态数组;普通队列;栈;链表;哈希表;
树形结构:二分搜索树;AVL树;红黑树;堆;线段树;Trie ;并查集;
图结构:邻接表;邻接矩阵;
抽象数据结构:线性表:动态数组、链表; 栈;队列;集合;映射(有序、无序);
冒泡排序
int temp = 0; boolean flag = false; for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { flag = true; temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } if (!flag) { break; } else { flag = false; } } }
选择排序
public static void SelectSort(int [] arr,int n){ for (int i = 0; i < n - 1; i++) { int index = i; int j; // 找出最小值得元素下标 for (j = i + 1; j < n; j++) { if (arr[j] < arr[index]) { index = j; } } int tmp = arr[index]; arr[index] = arr[i]; arr[i] = tmp; System.out.println(Arrays.toString(arr)); } }
删除链表中的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动
示例 1:
输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode deleteNode(ListNode head, int val) { ListNode dumhead=new ListNode(-1); dumhead.next=head; ListNode prev=dumhead; while(prev.next!=null) { if(prev.next.val==val) prev.next=prev.next.next; else prev=prev.next; } return dumhead.next; } }
解题思路:
首先定义一个虚拟节点,用来指向头结点的前面;
之后使用虚拟的节点表示出头结点;
定义一个节点表示指针,用来遍历链表;
反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
限制:
0 <= 节点个数 <= 5000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode reverseList(ListNode head) { if(head==null || head.next==null) return head; ListNode cur=reverseList(head.next); head.next.next=head; head.next=null; return cur; } }
解题思路:
主要是利用的递归的思想,栈的本质就是递归。
主要难点就是递归的出口以及翻转的条件
出口就是当链表为null 则结束;
翻转的条件很关键:head.next.next=head; 这句话可以利用三个数字进行验证。 比如 1,2,3 ;
移除链表元素
删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6 输出: 1->2->3->4->5
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ //方式一:使用虚拟头结点表示 class Solution { public ListNode removeElements(ListNode head, int val) { ListNode dumhead=new ListNode(-1); dumhead.next=head; ListNode prev=dumhead; //这里假如特判head.next==null;的话 测试用例[1] 1,会无法通过,,, //解决办法:要么不进行特判,要么只判断head==null的情况。 // if(head==null || head.next==null) // return head; while(prev.next!=null){ if(prev.next.val==val) prev.next=prev.next.next; else prev=prev.next; } return dumhead.next; } }
//方式二:使用递归调用解决问题
class Solution { public ListNode removeElements(ListNode head, int val) { if(head==null) return head; if(head.val==val) return removeElements(head.next,val); head.next=removeElements(head.next,val); return head; } }
解题思路:在head之前创建一个虚拟的节点;之后创建一个指针变量指向虚拟节点,用来遍历所有的链表元素。
递归实现两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
1->2->3->4 2->1->4->3 1 2 /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode swapPairs(ListNode head) { if(head==null || head.next==null) return head; ListNode temp=head.next; head.next=swapPairs(temp.next); temp.next=head; return temp; } }
杨辉三角
给定一个非负整数 *numRows,*生成杨辉三角的前 numRows 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 5 输出: [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ]
class Solution { public List<List<Integer>> generate(int numRows) { List<List<Integer>> triangle = new ArrayList<List<Integer>>(); if (numRows == 0) { return triangle; } triangle.add(new ArrayList<>()); triangle.get(0).add(1); for (int rowNum = 1; rowNum < numRows; rowNum++) { List<Integer> row = new ArrayList<>(); List<Integer> prevRow = triangle.get(rowNum-1); row.add(1); for (int j = 1; j < rowNum; j++) { row.add(prevRow.get(j-1) + prevRow.get(j)); } row.add(1); triangle.add(row); } return triangle; } }
解题思路:判断数值是否是第一位或者是最后一位,不是的话 那值就是 递归调用公式( [i-1] [j-1] + [i-1] [j] );
移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) { print(nums[i]); }
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-element
class Solution { public int removeElement(int[] nums, int val) { int j=0; for(int i =0 ;i<nums.length;i++) { if(nums[i]!=val) { nums[j]=nums[i]; j++; } } return j; } }
解题思路:主要就是 覆盖 ;
移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/move-zeroes
class Solution { public void moveZeroes(int[] nums) { if(nums==null || nums.length==0) return; int i=0,j=0; for(i=0;i<nums.length;i++){ if(nums[i]!=0){ nums[j]=nums[i]; j++; } } for(i=j;i<nums.length;i++) nums[i]=0; } }
判断子序列
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
示例 1:
s = “abc”, t = “ahbgdc”
返回 true.
示例 2:
s = “axc”, t = “ahbgdc”
返回 false.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/is-subsequence
class Solution { public boolean isSubsequence(String s, String t) { int i=s.length(); int j=t.length(); if(i==0) return true; if(i>j) return false; int is=0,it=0; while(it<j){ if(t.charAt(it)==s.charAt(is)){ is++; if(is==i) return true; } it++; } return false; } }
解题思路:主要就是利用双指针的思想;
分别创建两个变量,用来指向两个字符串的首个字符,然后对字符串长的进行遍历,对比短字符串的每一位,相同则返回true;
二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/
15 7
返回它的最大深度 3 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public int maxDepth(TreeNode root) { if(root==null) return 0; else { int leftHight=maxDepth(root.left); int rightHight=maxDepth(root.right); return Math.max(leftHight,rightHight)+1; } } }
解题思路:采取递归的策略,对每一个节点都调用maxDepth函数,最后求解左右高度的最大值即可。
平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/
9 20
/
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/
2 2
/
3 3
/
4 4
返回 false 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/balanced-binary-tree
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public boolean isBalanced(TreeNode root) { if (root == null) return true; return Math.abs(depth(root.left) - depth(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right); } private int depth(TreeNode root) { if (root == null) return 0; return Math.max(depth(root.left), depth(root.right)) + 1; } }
解题思路:采取递归求解;定义一个方法求解树的高度,递归调用; 保证每一个节点的左右子树都是平衡树
两个数组的交集
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
说明:
输出结果中的每个元素一定是唯一的。
我们可以不考虑输出结果的顺序。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-of-two-arrays
import java.util.TreeSet; class Solution { public int[] intersection(int[] nums1, int[] nums2) { TreeSet<Integer> set=new TreeSet<>(); for(int nums:nums1){ set.add(nums); } ArrayList<Integer> list=new ArrayList<>(); for(int num:nums2){ if(set.contains(num)){ list.add(num); set.remove(num); } } int res[]=new int[list.size()]; for(int i=0;i<list.size();i++){ res[i]=list.get(i); } return res; } }
解题思路:由于是要求解两个数组的交集,又要求唯一,自然而然想到了set集合;
这里使用一个集合,将数组1中所有元素加进集合;对第二个数组进行遍历,判断集合中是否存在数组中的元素,存在的话新建一个list集合保存下来,之后移除set中已经存在的元素;最后遍历list中的元素,保存到新的数组中即可;
重建二叉树
输入一棵二叉树前序遍历和中序遍历的结果,请重建该二叉树。
注意:
二叉树中每个节点的值都互不相同;
输入的前序遍历和中序遍历一定合法;
样例
给定: 前序遍历是:[3, 9, 20, 15, 7] 中序遍历是:[9, 3, 15, 20, 7] 返回:[3, 9, 20, null, null, 15, 7, null, null, null, null] 返回的二叉树如下所示: 3 / \ 9 20 / \ 15 7
/** * Definition for a binary tree node. * class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode buildTree(int[] pre, int[] in) { if(pre.length == 0 || in.length == 0 || pre.length != in.length) { return null; } // 拿到根结点 TreeNode root = new TreeNode(pre[0]); // 找的根结点在中序遍历中的位置 int i = 0; while(in[i] != root.val) { i++; } //确定左子树前序遍历长度 int[] preLeft = new int[i]; //确定左子树中序遍历长度 int[] inLeft = new int[i]; //确定右子树前序遍历长度 int[] preRight = new int[in.length - i -1]; //确定右子树中序遍历长度 int[] inRight = new int[in.length - i -1]; // 遍历 依次拿到左右子树 前中序遍历的值 for(int j = 0 ; j<in.length ;j++) { if(j < i) { preLeft[j] = pre[j+1]; inLeft[j] = in[j]; }else if(j > i) { preRight[j-i-1] = pre[j]; inRight[j-i-1] = in[j]; } } // 递归 root.left = buildTree(preLeft,inLeft); root.right = buildTree(preRight,inRight); return root; } }
有关(大小)堆的一些随笔
大顶堆
首先可以使用数组存起每一个节点,利用索引表示根节点与左右子树之间的关系;
关系为:根节点=index(可以从零开始,后边的左右子树表示时 减去1 即可);左子树=index*2;右子树=index*2+1;
1.插入add插入元素到堆尾,然后上浮
2.删除 remove 将堆首与堆尾交换,之后删掉堆尾,然后堆首下沉/上浮
3.上浮 ;比较该节点与其父节点大小,若不符合大顶堆的根节点最大原则,则与根节点交换位置,并且指向该父节点,继续循环比较至堆顶
4.下沉:比较父节点与左右子节点,交换不符合顺序的根节点,之后指向子节点,直至最后
大顶堆 原则上与大顶堆相同;
魔术索引
魔术索引。 在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。
示例1:
输入:nums = [0, 2, 3, 4, 5]
输出:0
说明: 0下标的元素为0
示例2:
输入:nums = [1, 1, 1]
输出:1
说明:
nums长度在[1, 1000000]之间
此题为原书中的 Follow-up,即数组中可能包含重复元素的版本
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/magic-index-lcci
class Solution { public int findMagicIndex(int[] nums) { if(nums==null || nums.length==0) return -1; for(int i=0;i<nums.length;i++){ if(nums[i]==i) return i; } return -1; } }
解题思路:由于题目中数组是有序的,所以返回值一定就是最小的答案。
二叉树的镜像
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4
/
2 7
/ \ /
1 3 6 9
镜像输出:
4
/
7 2
/ \ /
9 6 3 1
示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
限制:
0 <= 节点个数 <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode mirrorTree(TreeNode root) { if(root==null) return null; return swap(root); } private TreeNode swap(TreeNode node){ if(node==null) return null; if( node.left!=null || node.right!=null){ TreeNode newnode=new TreeNode(); newnode=node.left; node.left=node.right; node.right=newnode; swap(node.left); swap(node.right); } return node; } }
解题思路:主要还是使用递归思想;对每一个节点都进行判断;如果有左子树或者右子树就进行节点之间的交换即可。
对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/
2 2
/ \ /
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/
2 2
\
3 3
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
限制:
0 <= 节点个数 <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/dui-cheng-de-er-cha-shu-lcof
class Solution { public boolean isSymmetric(TreeNode root) { if(root==null) return true; return recur(root.left,root.right); } boolean recur(TreeNode L, TreeNode R) { if(L == null && R == null) return true; if(L == null || R == null || L.val != R.val) return false; return recur(L.left, R.right) && recur(L.right, R.left); } }
二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ import java.util.*; class Solution { public List<List<Integer>> levelOrder(TreeNode root) { if(root==null) { return new ArrayList<List<Integer>>(); } List<List<Integer>> res = new ArrayList<List<Integer>>(); LinkedList<TreeNode> queue = new LinkedList<TreeNode>(); //将根节点放入队列中,然后不断遍历队列 queue.add(root); while(queue.size()>0) { //获取当前队列的长度,这个长度相当于 当前这一层的节点个数 int size = queue.size(); ArrayList<Integer> tmp = new ArrayList<Integer>(); //将队列中的元素都拿出来(也就是获取这一层的节点),放到临时list中 //如果节点的左/右子树不为空,也放入队列中 for(int i=0;i<size;++i) { TreeNode t = queue.remove(); tmp.add(t.val); if(t.left!=null) { queue.add(t.left); } if(t.right!=null) { queue.add(t.right); } } //将临时list加入最终返回结果中 res.add(tmp); } return res; } }
二叉树的中序遍历
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [1,3,2]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<Integer> inorderTraversal(TreeNode root) { List list=new ArrayList<>(); if(root==null) return list; return help(root,list); } private List help(TreeNode node, List list){ if(node==null) return list; help(node.left,list); list.add(node.val); help(node.right,list); return list; } }
二叉树的后序遍历
给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [3,2,1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-postorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> list=new ArrayList<Integer>(); if(root==null) return list; return help(root,list); } private List<Integer> help(TreeNode node , List<Integer> list){ if(node==null) return list; help(node.left,list); help(node.right,list); list.add(node.val); return list; } }
二叉树的前序遍历
给定一个二叉树,返回它的 前序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [1,2,3]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal
递归实现:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> list = new ArrayList<>(); if(root ==null) return list; help(root,list); return list; } public List<Integer> help(TreeNode node ,List<Integer> list){ if(node==null )return list; list.add(node.val); help(node.left,list); help(node.right,list); return list; } }
迭代实现:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> list = new ArrayList<Integer>(); Stack<TreeNode> stack = new Stack<>(); if(root == null) return list; stack.push(root); while(!stack.isEmpty()){ root = stack.pop(); list.add(root.val); if(root.right != null) stack.push(root.right); if(root.left != null) stack.push(root.left); } return list; } }
二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root==null || q==root || p==root) return root; TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); if(left == null) return right; if(right == null) return left; return root; } }
二叉树的深度
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最大深度 3 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public int maxDepth(TreeNode root) { if(root==null) return 0; return help(root); } private int help(TreeNode node){ if(node==null) return 0; int left=help(node.left); int right= help(node.right); return Math.max(left,right)+1; } }
飞地的数量
给出一个二维数组 A,每个单元格为 0(代表海)或 1(代表陆地)。
移动是指在陆地上从一个地方走到另一个地方(朝四个方向之一)或离开网格的边界。
返回网格中无法在任意次数的移动中离开网格边界的陆地单元格的数量。
示例 1:
输入:[[0,0,0,0],[1,0,1,0],[0,1,1,0],[0,0,0,0]]
输出:3
解释:
有三个 1 被 0 包围。一个 1 没有被包围,因为它在边界上。
示例 2:
输入:[[0,1,1,0],[0,0,1,0],[0,0,1,0],[0,0,0,0]]
输出:0
解释:
所有 1 都在边界上或可以到达边界。
提示:
1 <= A.length <= 500
1 <= A[i].length <= 500
0 <= A[i][j] <= 1
所有行的大小都相同
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-enclaves
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution { int dire[][]={{-1,0},{0,1},{1,0},{0,-1}}; int row; int col; int [][] A; public int numEnclaves(int[][] A) { this.A=A; if(A==null || A.length==0) return 0; row=A.length; col=A[0].length; int ret=0; for(int i=0;i<row;i++){ if(A[i][0]==1){ helper(i,0); } if(A[i][col-1]==1) { helper(i,col-1); } } for(int i=0;i<col;i++){ if(A[0][i]==1){ helper(0,i); } if(A[row-1][i]==1){ helper(row-1,i); } } for(int i=0;i<row;i++){ for(int j=0;j<col;j++){ if(A[i][j]==1) ret++; } } return ret; } public void helper(int i,int j){ if(i<0 || i>=row || j<0 || j>=col || A[i][j]==0) return; A[i][j]=0; for(int k=0;k<4;k++){ int x=dire[k][0]+i; int y=dire[k][1]+j; helper(x,y); } } }
岛屿数量
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:
[
[‘1’,‘1’,‘1’,‘1’,‘0’],
[‘1’,‘1’,‘0’,‘1’,‘0’],
[‘1’,‘1’,‘0’,‘0’,‘0’],
[‘0’,‘0’,‘0’,‘0’,‘0’]
]
输出: 1
示例 2:
输入:
[
[‘1’,‘1’,‘0’,‘0’,‘0’],
[‘1’,‘1’,‘0’,‘0’,‘0’],
[‘0’,‘0’,‘1’,‘0’,‘0’],
[‘0’,‘0’,‘0’,‘1’,‘1’]
]
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-islands
class Solution { int dir[][]={{-1,0},{0,1},{1,0},{0,-1}}; boolean [][] visted; char[][] grid; int R; int C; public int numIslands(char[][] grid) { R=grid.length; if(R==0 ) return 0; C=grid[0].length; visted=new boolean[R][C]; this.grid=grid; int res=0; for(int i=0;i<R;i++){ for(int j=0;j<C;j++){ if(grid[i][j]=='1' && !visted[i][j]){ visted[i][j]=true; res++; bfs(i,j); } } } return res; } private void bfs(int i,int j){ visted[i][j]=true; for(int d=0;d<4;d++){ int x=i+dir[d][0]; int y=j+dir[d][1]; if( inarea(x,y)&& grid[x][y]=='1' && !visted[x][y] ){ bfs(x,y); } } } private boolean inarea(int x,int y){ return x>=0 && y>=0 && x<R && y<C; } }
将有序数组转化为二叉搜索树
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:
0
/
-3 9
/ /
-10 5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode sortedArrayToBST(int[] nums) { return help(nums, 0, nums.length - 1); } public TreeNode help(int[] nums, int left, int right) { if (left > right || nums==null || nums.length==0) { return null; } int mid = (left + right) / 2; TreeNode root = new TreeNode(nums[mid]); root.left = help(nums, left, mid - 1); root.right = help(nums, mid + 1, right); return root; } }
判断二分图
给定一个无向图graph,当这个图为二分图时返回true。
如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。
graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值。
示例 1:
输入: [[1,3], [0,2], [1,3], [0,2]]
输出: true
解释:
无向图如下:
0----1
| |
| |
3----2
我们可以将节点分成两组: {0, 2} 和 {1, 3}。
示例 2:
输入: [[1,2,3], [0,2], [0,1,3], [0,2]]
输出: false
解释:
无向图如下:
0----1
| \ |
| \ |
3----2
我们不能将节点分割成两个独立的子集。
注意:
graph 的长度范围为 [1, 100]。
graph[i] 中的元素的范围为 [0, graph.length - 1]。
graph[i] 不会包含 i 或者有重复的值。
图是无向的: 如果j 在 graph[i]里边, 那么 i 也会在 graph[j]里边。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/is-graph-bipartite
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution { private int[] colors; private int[][] graph; private boolean[] visited; public boolean isBipartite(int[][] graph) { this.graph=graph; int V=graph.length; visited=new boolean[V]; colors=new int[V]; for (int v = 0; v <V ; v++) { if(!visited[v]) if(!dfs(v,0)) return false; } return true; } private boolean dfs(int v, int color) { visited[v]=true; colors[v]=color; for (int w:graph[v]) { if(!visited[w]){ if(!dfs(w,1-color)) return false; } if(colors[v]==colors[w]) return false; } return true; } }
N叉树的层序遍历
给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。
例如,给定一个 3叉树 :
返回其层序遍历:
[
[1],
[3,2,4],
[5,6]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/* // Definition for a Node. class Node { public int val; public List<Node> children; public Node() {} public Node(int _val) { val = _val; } public Node(int _val, List<Node> _children) { val = _val; children = _children; } }; */ class Solution { public List<List<Integer>> levelOrder(Node root) { List<List<Integer>> result = new ArrayList<>(); if (root == null) return result; Queue<Node> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { List<Integer> level = new ArrayList<>(); int size = queue.size(); for (int i = 0; i < size; i++) { Node node = queue.poll(); level.add(node.val); queue.addAll(node.children); } result.add(level); } return result; } }
N叉树的后序遍历
给定一个 N 叉树,返回其节点值的后序遍历。
例如,给定一个 3叉树 :
返回其后序遍历: [5,6,3,2,4,1].
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/* // Definition for a Node. class Node { public int val; public List<Node> children; public Node() {} public Node(int _val) { val = _val; } public Node(int _val, List<Node> _children) { val = _val; children = _children; } }; */ class Solution { List res=new ArrayList(); public List<Integer> postorder(Node root) { if(root ==null) return res; help(root); return res; } private void help(Node node){ if(node==null) return ; if(node.children!=null){ int s=node.children.size(); for(int i=0;i<s;i++) help(node.children.get(i)); } res.add(node.val); } }
N叉树的前序遍历
给定一个 N 叉树,返回其节点值的前序遍历。
例如,给定一个 3叉树 :
返回其前序遍历: [1,3,5,6,2,4]。
/* // Definition for a Node. class Node { public int val; public List<Node> children; public Node() {} public Node(int _val) { val = _val; } public Node(int _val, List<Node> _children) { val = _val; children = _children; } }; */ class Solution { List res=new ArrayList(); public List<Integer> preorder(Node root) { if(root==null) return res; help(root); return res; } private void help(Node node){ if(node==null) return ; res.add(node.val); if(node.children!=null){ int s=node.children.size(); for(int i=0;i<s;i++){ help(node.children.get(i)); } } } }
类似二叉树的前序遍历
相同的树
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入:
1 1
/ \ /
2 3 2 3
[1,2,3], [1,2,3]
输出: true
示例 2:
输入:
1 1
/
2 2
[1,2], [1,null,2]
输出: false
示例 3:
输入:
1 1
/ \ /
2 1 1 2
[1,2,1], [1,1,2]
输出: false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/same-tree
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { public boolean isSameTree(TreeNode p, TreeNode q) { if(p==null && q==null) return true; if(p==null || q==null) return false; if(p.val!=q.val) return false; return isSameTree(p.left,q.left)&& isSameTree(p.right,q.right); } }
第一个只出现一次的字符
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
示例:
s = “abaccdeff”
返回 “b”
s = “”
返回 " "
限制:
0 <= s 的长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof
class Solution { public char firstUniqChar(String s) { if(s==null) return ' '; int fren[]=new int[26]; for(int i=0;i<s.length();i++) fren[s.charAt(i)-'a']++; for(int i=0;i<s.length();i++) if(fren[s.charAt(i)-'a']==1) return s.charAt(i); return ' '; } }
解题思路:由于题目给出了一个条件( s 只包含小写字母。)所以可以利用数组将26个字母全部存储,每一个索引从a–z一一对应;
之后再次遍历字符串,找到所有字符中只出现一次的字母,返回即可。
很多人用的都是哈希表解题,这题的初衷也是训练有关哈希表的理解,我这里使用数组只是帮助自己对哈希表理解起来简单点而已。
红黑树性质
害 也就是一些生硬的定义…
在定义数据结构时 默认的初始值应该是红色;红黑树跟2-3树是等价的
2-3树中若某节点为红色 则表示该节点是与父节点相融合的,也就是3节点形式。
以下所有描述都可以参考上图进行理解:
1.每个节点或者是红色的,或者是黑色的
2.根节点是黑色的
3.每一个叶子节点(最后的空节点)是黑色的
4.如果一个节点是红色的,那么他的孩子节点都是黑色的
5.从任意一个节点到叶子节点,经过的黑色节点数量是一样的
罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 1:
输入: “III”
输出: 3
示例 2:
输入: “IV”
输出: 4
示例 3:
输入: “IX”
输出: 9
示例 4:
输入: “LVIII”
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:
输入: “MCMXCIV”
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/roman-to-integer
import java.util.*; class Solution { public int romanToInt(String s) { int sum = 0; int preNum = getValue(s.charAt(0)); for(int i = 1;i < s.length(); i ++) { int num = getValue(s.charAt(i)); if(preNum < num) { sum -= preNum; } else { sum += preNum; } preNum = num; } sum += preNum; return sum; } private int getValue(char ch) { switch(ch) { case 'I': return 1; case 'V': return 5; case 'X': return 10; case 'L': return 50; case 'C': return 100; case 'D': return 500; case 'M': return 1000; default: return 0; } } }