文章目录
- 3. 无重复字符的最长子串
- 2. 两数相加
- 5. 最长回文子串
- 15. 三数之和
- 11. 盛最多水的容器
- 31. 下一个排列
- 54. 螺旋矩阵
- 56. 合并区间
- 46. 全排列
- 143. 重排链表
- 199. 二叉树的右视图
- 92. 反转链表 II
- 33. 搜索旋转排序数组
- 103. 二叉树的锯齿形层序遍历
- 200. 岛屿数量
- 19. 删除链表的倒数第 N 个结点
- 22. 括号生成
- 148. 排序链表
- 105. 从前序与中序遍历序列构造二叉树
- 215. 数组中的第K个最大元素
- 221. 最大正方形
- 24. 两两交换链表中的节点
- 快排
- 实现二叉树前中后三序遍历
- 最小的k个数
- 二叉树层次遍历
- 寻找第K大
- 两数之和
- 最长无重复子串
- 判断链表是否有环
- 判断环的入口
- 删除链表的倒数第N个结点
- Z形遍历二叉树
- 最长公共子串
- 两个链表相加
- 找到两个二叉树的公共父节点
- 最长回文子串
- 三数之和
- 重构二叉树
- 搜索排序后的数
- 合并K个有序链表
- 盛水的容器
- 输出右视图
- 岛屿数量
- 矩阵和的最小路径
- 求叶子节点到根节点所用的路径和
- 二叉树到叶子节点的指定路径和
- 链表指定区域内反转
- 合并区间
- 判断一棵树是否为搜索二叉树和满二叉树
- 删除有序列表出现重复的元素
- 矩阵元素的查找
- 数组中未出现的最小整数
- 链表奇偶重排序
- 括号生成
- 顺时针旋转矩阵
- LRU
3. 无重复字符的最长子串
通过定义一个set来进行非重复的一个判断,通过快慢双指针,右边的指针遇到不一样的就存到set里面,然后遇到一样的就停止,前面的指针就自动走,然后每次记得还要把set里面存的了数据进行一个移除
class Solution {
public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet<>();
int res = 0,len = s.length(),r = -1;
for(int i = 0 ;i < len ; i++ ){
if(i != 0){
set.remove(s.charAt(i-1));
}
while((r+1) < len && !set.contains(s.charAt(r+1))){
set.add(s.charAt(r+1));
r++;
}
res = Math.max(res , r - i + 1);
}
return res;
}
}
2. 两数相加
利用好进位,就可以收工
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode newhead = new ListNode(0);
ListNode tail = newhead;
int carray = 0;
while(l1!=null || l2!=null){
int x = l1 == null?0:l1.val;
int y = l2 == null?0:l2.val;
int z = x + y + carray;
carray = z / 10;
tail.next = new ListNode(z % 10);
tail = tail.next;
if(l1!=null) l1 = l1.next;
if(l2!=null) l2 = l2.next;
}
if(carray == 1) tail.next = new ListNode(1);
return newhead.next;
}
}
5. 最长回文子串
dp死记题
class Solution {
public String longestPalindrome(String s) {
if(s == null || s.length() < 2) return s ;
int start = 0;
int end = 0;
int value = 1;
int len = s.length();
boolean[][] dp = new boolean[len][len];
for(int r = 1 ; r < len ; r++){
for(int l = 0; l < r ; l++){
if(s.charAt(l)==s.charAt(r) && ((r - l )<= 2 || dp[l+1][r-1])){
dp[l][r] = true;
if(value < r - l +1){
value = r - l +1;
start = l;
end = r;
}
}
}
}
return s.substring(start,end+1);
}
}
15. 三数之和
找规律,不难
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
for(int k = 0 ; k< nums.length -2 ; k++){
if(nums[k] > 0 ) break;
if(k > 0 && nums[k] == nums[k-1]) continue;
int l = k +1 ,r = nums.length -1;
while(l < r){
int total = nums[k] + nums[l] + nums[r];
if(total < 0){
while(l < r && nums[l] == nums[++l]);
}else if(total > 0){
while(l < r && nums[r] == nums[--r]);
}else{
res.add(new ArrayList<Integer>(Arrays.asList(nums[k],nums[l],nums[r])));
while(l<r && nums[l] == nums[++l]);
while(l<r && nums[r] == nums[--r]);
}
}
}
return res;
}
}
11. 盛最多水的容器
每次记录一下面积就好了
class Solution {
public int maxArea(int[] height) {
int l = 0, r = height.length -1,res = 0;
while(l < r){
int s = Math.min(height[l],height[r])*(r-l);
res = Math.max(s,res);
if(height[l]<height[r]){
l++;
}else{
r--;
}
}
return res;
}
}
31. 下一个排列
通过i+1和j来分别和i进行比较,最后交换和反转一次就可以了
class Solution {
public void nextPermutation(int[] nums) {
if(nums == null || nums.length ==0) return;
int i = nums.length - 2;
while(i >= 0 && nums[i+1] <= nums[i]){
i--;
}
if(i >= 0){
int j = nums.length -1;
while(j >=0 && nums[j]<=nums[i]){
j--;
}
swap(nums,i,j);
}
resver(nums,i + 1,nums.length-1);
}
void resver(int[] nums,int i ,int j){
while(i<j){
swap(nums,i++,j--);
}
}
void swap(int[] nums,int i ,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
54. 螺旋矩阵
左上右下
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
if(matrix.length == 0 || matrix == null) return res;
int left = 0,up = 0;
int down = matrix.length-1,right = matrix[0].length-1;
while(left<= right && up <= down){
for(int i = left; i <= right && up <= down ; i++){
res.add(matrix[up][i]);
}
up++;
for(int i = up; i <= down && left <= right ; i++){
res.add(matrix[i][right]);
}
right--;
for(int i = right; i >= left && up <= down ; i--){
res.add(matrix[down][i]);
}
down--;
for(int i = down; i >= up && left <= right ; i--){
res.add(matrix[i][left]);
}
left++;
}
return res;
}
}
56. 合并区间
用后面一个数的第一个数是否小于前面一个数的后面一个数来进行范围的读取
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals,Comparator.comparingInt((a ->a[0])));
List<int[]> res = new ArrayList<>();
int i,j = 0,max;
while((i = j) < intervals.length){
max = intervals[i][1];
j = i;
while(j < intervals.length && intervals[j][0]<=max){
max = Math.max(max,intervals[j++][1]);
}
res.add(new int[]{intervals[i][0],max});
}
return res.toArray(new int[res.size()][2]);
}
}
46. 全排列
送分
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
boolean[] visited = new boolean[nums.length];
ArrayList<Integer> temp = new ArrayList<>();
dfs(nums,res,visited,temp);
return res;
}
void dfs(int[] nums,List<List<Integer>> res,boolean[] visited,ArrayList temp){
if(temp.size() == nums.length) res.add(new ArrayList(temp));
for(int i = 0 ;i < nums.length ; i++){
if(visited[i]) continue;
visited[i] = true;
temp.add(nums[i]);
dfs(nums,res,visited,temp);
visited[i] = false;
temp.remove(temp.size()-1);
}
}
}
143. 重排链表
通过一个list来辅助完成
class Solution {
public void reorderList(ListNode head) {
if(head == null || head.next == null ) return;
List<ListNode> list = new ArrayList<>();
ListNode cur = head;
while(cur!=null){
list.add(cur);
cur = cur.next;
}
int len = list.size() - 1;
//让cur重新回到head;
cur = head;
//这里除以2是因为我每次操作可以确定两个节点
for(int i = len; i > len/2 ;i--){
if(cur.next == null){
return;
}else {
ListNode tnext = cur.next;
cur.next = list.get(i);
list.get(i).next = tnext;
cur = tnext;
}
}
//最后后面为空
cur.next = null;
}
}
199. 二叉树的右视图
一个pdpt是否等于list的长度来判断是否只有一个加入就可以了
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> rightSideView(TreeNode root) {
dfs(root,0);
return res;
}
void dfs(TreeNode node,int dept){
if(node == null) return;
//这里就是为了确保左右子树同时存在的时候只会参照一个
if(res.size() == dept) res.add(node.val);
dept++;
dfs(node.right,dept);
dfs(node.left,dept);
}
}
92. 反转链表 II
双指针+头插法
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode newhead = new ListNode(0);
newhead.next = head;
ListNode l = newhead;
ListNode r = newhead.next;
for(int i = 0 ; i < m - 1 ;i++){
l = l.next;
r = r.next;
}
for(int i = 0;i < n - m ; i++){
ListNode temp = r.next;
r.next = r.next.next;
temp.next = l.next;
l.next = temp;
}
return newhead.next;
}
}
33. 搜索旋转排序数组
先判断左右的连续,然后二分法就可以了
class Solution {
//左边连续就在左边找,右边连续就在右边找
public int search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while(left <= right){
int mid = (left + right) / 2;
if(nums[mid] == target) return mid;
if(nums[mid] >= nums[left]){
if(target>=nums[left] && target <= nums[mid]){
right = mid -1;
}else{
left = mid+1;
}
}else {
if(target>=nums[mid] && target <= nums[right]){
left = mid+1;
}else{
right = mid-1;
}
}
}
return -1;
}
}
103. 二叉树的锯齿形层序遍历
思路就是利用一个templist来预先创建下一层要加入对象的容器,然后用dept来计算深度
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
dfs(res,root,0);
return res;
}
void dfs(List<List<Integer>> res,TreeNode root,int dept){
if(root == null) return;
//如果下一层没有的话,就创建
if(res.size()<=dept){
res.add(new ArrayList<Integer>());
}
//取出
List<Integer> temp = res.get(dept);
//判断加入的流程
if(dept%2 == 0){
temp.add(root.val);
}else{
temp.add(0,root.val);
}
//dfs
dfs(res,root.left,dept+1);
dfs(res,root.right,dept+1);
}
}
200. 岛屿数量
思路就是dfs到有1的地方就标记成0,然后上下左右跑就可以了
class Solution {
public int numIslands(char[][] grid) {
int count = 0;
//确定到有1的字符进行
for(int i = 0;i < grid.length ;i++){
for(int j = 0;j < grid[0].length ;j++){
if(grid[i][j] == '1'){
dfs(grid,i,j);
count++;
}
}
}
//dfs
return count;
}
void dfs(char[][] grid,int i,int j){
if(i<0 || j<0 || i>= grid.length || j >= grid[0].length || grid[i][j] == '0') return;
//开始标记走过的路径为0
grid[i][j] = '0';
//开始dfs直到遇到0或者越界的时候停止
dfs(grid,i+1,j);
dfs(grid,i,j+1);
dfs(grid,i-1,j);
dfs(grid,i,j-1);
}
}
19. 删除链表的倒数第 N 个结点
先获取长度,然后删除就可以了
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode newhead = new ListNode(0,head);
ListNode cur = newhead;
for(int i =0;i<getlen(newhead)-n;i++){
cur = cur.next;
}
cur.next = cur.next.next;
return newhead.next;
}
int getlen(ListNode node) {
int count = 0;
while (node.next != null) {
count++;
node = node.next;
}
return count;
}
}
22. 括号生成
利用回溯的思想,每次判断一下左括号是否没有了,以及右括号的个数是否大于左括号的个数即可
class Solution {
//创建容器
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
if(n <= 0) return res;
String temp = "";
//dfs
dfs(n,n,temp);
return res;
}
void dfs(int left,int right,String temp){
if(left == 0 && right == 0) res.add(temp);
//左边的括号可以一直放,右边的括号数量大于左边的括号的时候也可以放
if(left > 0) dfs(left - 1,right,temp + "(");
if(left < right) dfs(left,right -1 ,temp + ")");
}
}
148. 排序链表
用小顶堆的方式先存后取出,完美
class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null) return head;
//创建一个小顶堆
PriorityQueue<Integer> dui = new PriorityQueue<>();
//先存到小顶堆里面去
ListNode cur = head;
while(cur!=null){
dui.offer(cur.val);
cur = cur.next;
}
ListNode newhead = new ListNode(0);
ListNode tail = newhead;
//然后从小顶堆里面拿出来,插入新的节点
while(!dui.isEmpty()){
int temp = dui.poll();
ListNode tmp = new ListNode(temp);
tail.next = tmp;
tail = tail.next;
}
return newhead.next;
}
}
105. 从前序与中序遍历序列构造二叉树
注意一下小细节,Arrays.copyOfRange是左闭右开就可以了
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length == 0 || inorder.length == 0) return null;
//确定根节点
TreeNode root = new TreeNode(preorder[0]);
//找到inorder中根节点对应的位置
for(int i = 0 ;i < inorder.length ; i++){
if(root.val == inorder[i]){
//最后通过递归来break找到root
int[] pre_left = Arrays.copyOfRange(preorder,1,i+1);
int[] pre_right = Arrays.copyOfRange(preorder,i+1,preorder.length);
int[] ino_left = Arrays.copyOfRange(inorder,0,i);
int[] ino_right = Arrays.copyOfRange(inorder,i+1,inorder.length);
root.left = buildTree(pre_left,ino_left);
root.right = buildTree(pre_right,ino_right);
break;
}
}
return root;
}
}
215. 数组中的第K个最大元素
用堆进去再出来就可以了
class Solution {
public int findKthLargest(int[] nums, int k) {
//初始化
PriorityQueue<Integer> sdui = new PriorityQueue<>();
//循环
for(int i = 0; i < nums.length ; i++){
sdui.offer(nums[i]);
//判断
if(sdui.size()>k) sdui.poll();
}
//返回值
return sdui.poll();
}
}
221. 最大正方形
这题就是dp,死记,思想就是通过右下角来先选出最小的+1,然后再选出最大的
class Solution {
public int maximalSquare(char[][] matrix) {
if(matrix == null || matrix.length == 0 || matrix[0].length == 0) return 0;
//初始化边界
int height = matrix.length;
int weight = matrix[0].length;
int max = 0;
//初始化dp
int[][] dp = new int[height+1][weight+1];
//如果为1,选出最小的dp
for(int row = 0 ; row < height ; row++){
for(int col = 0 ; col < weight ; col++){
if(matrix[row][col] == '1'){
dp[row+1][col+1] =Math.min(Math.min(dp[row+1][col],dp[row][col+1]),dp[row][col])+1;
max = Math.max(dp[row+1][col+1],max);
}
}
}
return max * max;
}
}
24. 两两交换链表中的节点
这个题有点奇怪,但是看着图,分析一下,简单领出来一个2就可以手工了!
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null) return head;
//把2先领出来
ListNode nexttemp = head.next;
//1指向4
head.next = swapPairs(nexttemp.next);
//2指向1
nexttemp.next = head;
return nexttemp;
}
}
快排
注意一下在里面的while是大于等于
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型一维数组 待排序的数组
* @return int整型一维数组
*/
public int[] MySort (int[] arr) {
quick(arr,0,arr.length-1);
return arr;
}
void quick(int[] arr,int start,int end){
if(start < end ){
int temp = arr[start];
int l = start;
int r = end;
while(l < r){
while(l < r && arr[r] >= temp){
r--;
}
arr[l] = arr[r];
while(l < r && arr[l] <= temp){
l++;
}
arr[r] = arr[l];
}
arr[l] = temp;
quick(arr,start,l);
quick(arr,l+1,end);
}
}
}
实现二叉树前中后三序遍历
不难,就是代码稍微多一点
import java.util.*;
public class Solution {
public ArrayList<Integer> first = new ArrayList<>();
public ArrayList<Integer> middle = new ArrayList<>();
public ArrayList<Integer> then = new ArrayList<>();
/**
*
* @param root TreeNode类 the root of binary tree
* @return int整型二维数组
*/
public int[][] threeOrders (TreeNode root) {
firstOrder(root);
middleOrder(root);
thenOrder(root);
int[][] result = new int[3][first.size()];
result[0]=toIntArray(first);
result[1]=toIntArray(middle);
result[2]=toIntArray(then);
return result;
}
//ArrayList 转 int[]
public int[] toIntArray(ArrayList<Integer> list){
if(list==null||list.size()<1){
return new int[0];
}
int[] result=new int[list.size()];
for(int i=0;i<list.size();i++){
result[i]=list.get(i);
}
return result;
}
//先序遍历
public void firstOrder(TreeNode root){
//跳出条件
if(root==null){
return;
}
first.add(root.val);
firstOrder(root.left);
firstOrder(root.right);
}
//中序遍历
public void middleOrder(TreeNode root){
//跳出条件
if(root==null){
return;
}
middleOrder(root.left);
middle.add(root.val);
middleOrder(root.right);
}
//后序遍历
public void thenOrder(TreeNode root){
//跳出条件
if(root==null){
return;
}
thenOrder(root.left);
thenOrder(root.right);
then.add(root.val);
}
}
最小的k个数
这个题目,估计要自己去实现堆
import java.util.ArrayList;
import java.util.PriorityQueue;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
PriorityQueue<Integer> zxd = new PriorityQueue<>();
ArrayList<Integer> res = new ArrayList<>();
if(k > input.length ) return res;
for(int data : input){
zxd.offer(data);
}
for(int i = 0; i < k;i++ ){
res.add(zxd.poll());
}
return res;
}
}
二叉树层次遍历
记得用队列就行,简单完成
import java.util.*;
public class Solution {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
if(root == null ) return res;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
ArrayList<Integer> list = new ArrayList<>();
for(int i = 0 ; i < size ; i++){
TreeNode temp = queue.poll();
list.add(temp.val);
if(temp.left!=null) queue.offer(temp.left);
if(temp.right!=null) queue.offer(temp.right);
}
res.add(list);
}
return res;
}
}
寻找第K大
==在快排的结束阶段,加上了k-1的判断,在中途阶段,也对于大小进行了一个修改
import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
return quick(a,0,n-1,K);
}
int quick(int[] arr, int start, int end,int k){
if(start <= end){
int l = start;
int r = end;
int temp = arr[start];
while(l < r){
while(l < r && arr[r] <= temp){
r--;
}
if(l < r ){
arr[l++] = arr[r];
}
while(l < r && arr[l] > temp){
l++;
}
if(l < r ){
arr[r--] = arr[l];
}
}
arr[l] = temp;
if(l == k - 1){
return arr[l];
}
if(l < k - 1){
return quick(arr,l + 1,end,k);
}
if(l > k-1){
return quick(arr,start,l-1,k);
}
}
return -1;
}
}
两数之和
看清楚输出的下标就可以了
import java.util.*;
import java.util.Map;
public class Solution {
public int[] twoSum (int[] numbers, int target) {
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0 ; i < numbers.length; i++){
if(map.containsKey(target - numbers[i]))
return new int[]{map.get(target - numbers[i])+1,i+1};
map.put(numbers[i],i);
}
return new int[]{-1,-1};
}
}
最长无重复子串
用一个set存一下就可以了,结合双指针
import java.util.*;
public class Solution {
public int maxLength (int[] arr) {
// write code here
Set<Integer> set = new HashSet<>();
int k = -1,res = 0;
for(int i = 0 ;i < arr.length ;i++){
if(i!=0){
set.remove(arr[i-1]);
}
while((k+1)<arr.length && !set.contains(arr[k+1])){
set.add(arr[k+1]);
k++;
}
res = Math.max(res,k - i + 1);
}
return res;
}
}
判断链表是否有环
快慢指针搞定,边界用快指针搞定
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null) return false;
ListNode left = head;
ListNode right = head;
while(right!=null && right.next !=null){
left = left.next;
right = right.next.next;
if(left == right) return true;
}
return false;
}
}
判断环的入口
就是在原有环的基础上,然后进行了一个位置的判断,让left重新回到起点再过来一次
public class Solution {s
public ListNode detectCycle(ListNode head) {
ListNode left = head;
ListNode right = head;
while(right != null && right.next != null){
left = left.next;
right = right.next.next;
if(left == right){
left = head;
while(left!=right){
left = left.next;
right = right.next;
}
break;
}
}
if(right == null || right.next == null) return null;
return left;
}
}
删除链表的倒数第N个结点
这里一定要注意搞一个newhead,不然当个数很少的时候会出错
import java.util.*;
public class Solution {
public ListNode removeNthFromEnd (ListNode head, int n) {
// write code here
//如果不定义新节点,为1或者为0的情况就不好搞
ListNode newhead = new ListNode(0);
newhead.next = head;
ListNode left = newhead,right = newhead;
for(int i = 0 ;i <= n ; i++){
left = left.next;
}
while(left!=null){
left = left.next;
right = right.next;
}
right.next = right.next.next;
return newhead.next;
}
}
Z形遍历二叉树
核心思想就是创建一个list,然后获取,最后存数据
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer>> zigzagLevelOrder (TreeNode root) {
// write code here
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
dfs(res,root,0);
return res;
}
void dfs(ArrayList<ArrayList<Integer>> res ,TreeNode root,int dept){
if(root == null) return;
//如果下层没有就创建list
if(res.size()<=dept){
res.add(new ArrayList<Integer>());
}
//获取list
ArrayList<Integer> list = res.get(dept);
//往list里面分类添加元素
if(dept %2 ==0){
list.add(root.val);
}else {
list.add(0,root.val);
}
dfs(res,root.left,dept+1);
dfs(res,root.right,dept+1);
}
}
最长公共子串
思路也很简单,就是用双指针,后面的指针一直动,前面的之前的指针依据是否包含来进行移动
import java.util.*;
public class Solution {
public String LCS (String str1, String str2) {
// write code here
String res = "";
int left = 0,right = 1;
while(right <= str2.length()){
String temp = str2.substring(left,right);
if(str1.contains(temp)){
res = temp;
}else{
left++;
}
right++;
}
return res;
}
}
两个链表相加
跟之前的两数相加有点像
import java.util.*;
public class Solution {
public ListNode addInList (ListNode head1, ListNode head2) {
// write code here
head1 = reverse(head1);
head2 = reverse(head2);
ListNode head = new ListNode(-1);
ListNode cur = head;
int carry = 0;
while(head1 != null || head2 != null) {
int val = carry;
if (head1 != null) {
val += head1.val;
head1 = head1.next;
}
if (head2 != null) {
val += head2.val;
head2 = head2.next;
}
cur.next = new ListNode(val % 10);
carry = val / 10;
cur = cur.next;
}
if (carry > 0) {
cur.next = new ListNode(carry);
}
return reverse(head.next);
}
private ListNode reverse(ListNode head) {
ListNode cur = head;
ListNode pre = null;
while(cur != null) {
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
找到两个二叉树的公共父节点
这里唯一的区别就是需要我们去确定一下node
import java.util.*;
public class Solution {
public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
// write code here
TreeNode res = lowestCommon(root, o1, o2);
return res == null ? -1 : res.val;
}
public TreeNode lowestCommon(TreeNode root, int o1, int o2) {
if (root == null || root.val == o1 || root.val == o2) return root;
TreeNode left = lowestCommon(root.left, o1, o2);
TreeNode right = lowestCommon(root.right, o1, o2);
if (left == null)return right;
if (right == null)return left;
return root;
}
}
最长回文子串
思路就是动态规划,然后记录一下左右的值,如果相等就移动
import java.util.*;
public class Solution {
public int getLongestPalindrome(String A, int n) {
char[] ch = A.toCharArray();
int res = 0;
for(int i = 0; i < n ;i++){
int l = i,r = i;
while(l - 1 >= 0 && ch[l - 1]==ch[i]) l--;
while(r + 1 < n && ch[r + 1]==ch[i]) r++;
while(l - 1 >= 0 && r + 1 < n && ch[l - 1]==ch[r + 1]){
l--;
r++;
}
res = Math.max(res,r - l + 1);
}
return res;
}
}
三数之和
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
for(int i = 0;i < nums.length-2 ;i++){
if(nums[i] > 0) break;
if(i > 0 && nums[i] == nums[i-1]) continue;
int l = i + 1,r = nums.length - 1;
while(l < r){
int total = nums[i] + nums[l] + nums[r];
if(total < 0){
while(l < r && nums[l] == nums[++l]);
}else if(total>0){
while(l < r && nums[r] == nums[--r]);
}else{
res.add(new ArrayList<Integer>(Arrays.asList(nums[i],nums[l],nums[r])));
while(l < r && nums[l] == nums[++l]);
while(l < r && nums[r] == nums[--r]);
}
}
}
return res;
}
}
重构二叉树
确定一下下标的位置就可以了conpyOnRange
import java.util.*;
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre == null || in == null || pre.length == 0 || in.length == 0) return null;
TreeNode root = new TreeNode(pre[0]);
for(int i = 0;i < in.length ; i++){
if(root.val == in[i]){
int[] pre_left = Arrays.copyOfRange(pre,1,i+1);
int[] pre_right = Arrays.copyOfRange(pre,i+1,pre.length);
int[] in_left = Arrays.copyOfRange(in,0,i);
int[] in_right = Arrays.copyOfRange(in,i+1,in.length);
root.left = reConstructBinaryTree(pre_left,in_left);
root.right = reConstructBinaryTree(pre_right,in_right);
break;
}
}
return root;
}
}
搜索排序后的数
先判断范围,然后再二分一下就可以了
import java.util.*;
public class Solution {
public int search (int[] nums, int target) {
int left = 0 , right = nums.length - 1;
while(left <= right){
int mid = (left + right) / 2;
if(nums[mid] == target) return mid;
//左边是连续的
if(nums[mid] >= nums[left]){
if(nums[left]<=target && nums[mid]>=target){
right = mid - 1;
}else{
left = mid + 1;
}
}else{
if(nums[mid]<=target && nums[right]>=target){
left = mid + 1;
}else{
right = mid - 1;
}
}
}
return -1;
}
}
合并K个有序链表
思路就是先走一个二分,就可以了,记住是返回list.get(left)
import java.util.*;
public class Solution {
public ListNode mergeKLists(ArrayList<ListNode> lists) {
if(lists == null || lists.size() == 0) return null;
return rf(lists,0,lists.size() - 1);
}
ListNode rf(ArrayList<ListNode> lists,int left ,int right){
if(left >= right) return lists.get(left);
int mid = (left + right) / 2;
ListNode node1 = rf(lists,left,mid);
ListNode node2 = rf(lists,mid + 1,right);
ListNode res = merget(node1,node2);
return res;
}
ListNode merget(ListNode node1,ListNode node2){
if(node1 == null) return node2;
if(node2 == null) return node1;
if(node1.val <= node2.val){
node1.next = merget(node1.next,node2);
return node1;
}else{
node2.next = merget(node1,node2.next);
return node2;
}
}
}
盛水的容器
直接用一个lmax跟rmax就可以解决了
import java.util.*;
public class Solution {
public long maxWater (int[] arr) {
if(arr == null || arr.length == 0) return 0L;
int lmax = arr[0],rmax = arr[arr.length-1],l = 0,r = arr.length - 1;
Long res = 0L;
while(l < r){
lmax = Math.max(lmax,arr[l]);
rmax = Math.max(rmax,arr[r]);
if(lmax < rmax){
res += lmax - arr[l];
l++;
}else{
res += rmax - arr[r];
r--;
}
}
return res;
}
}
输出右视图
记住递归的时候以右边为主就可以了,如果size等于dept就代表只有一层,先存右侧的
import java.util.*;
public class Solution {
List<Integer> res = new ArrayList<>();
public int[] solve (int[] xianxu, int[] zhongxu) {
TreeNode root = cg(xianxu,zhongxu);
dfs(root,0);
int[] ints = new int[res.size()];
for(int i = 0; i < res.size() ;i++){
ints[i] = res.get(i);
}
return ints;
}
TreeNode cg(int[] pre, int[] in){
if(pre == null || in == null || pre.length == 0 || in.length == 0) return null;
TreeNode root = new TreeNode(pre[0]);
for(int i = 0;i < in.length ; i++){
if(root.val == in[i]){
int[] pre_left = Arrays.copyOfRange(pre,1,i+1);
int[] pre_right = Arrays.copyOfRange(pre,i+1,pre.length);
int[] in_left = Arrays.copyOfRange(in,0,i);
int[] in_right = Arrays.copyOfRange(in,i+1,in.length);
root.left = cg(pre_left,in_left);
root.right = cg(pre_right,in_right);
break;
}
}
return root;
}
void dfs(TreeNode node,int dept){
if(node == null) return;
if(res.size() == dept) res.add(node.val);
dept++;
//右视图,以右边的为主
dfs(node.right,dept);
dfs(node.left,dept);
}
}
岛屿数量
遇到1就停止,改成0就可以了
import java.util.*;
public class Solution {
public int solve (char[][] grid) {
if(grid == null || grid.length == 0) return 0;
int count = 0;
for(int i = 0;i < grid.length ;i++){
for(int j = 0; j< grid[0].length ;j++){
if(grid[i][j] == '1'){
count++;
dfs(grid,i,j);
}
}
}
return count;
}
void dfs(char[][] grid,int i ,int j){
if(i<0 || j<0 || i>=grid.length || j >=grid[0].length || grid[i][j] =='0') return;
grid[i][j] = '0';
dfs(grid,i+1,j);
dfs(grid,i,j+1);
dfs(grid,i-1,j);
dfs(grid,i,j-1);
}
}
矩阵和的最小路径
先把上下的边界给确定了,然后把中间的数填充一下就可以了,记得0,0也需要填充
import java.util.*;
public class Solution {
public int minPathSum (int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
int[][] dp = new int[m][n];
dp[0][0] = matrix[0][0];
for(int i = 1 ;i< n ;i++){
dp[0][i] = dp[0][i-1] + matrix[0][i];
}
for(int i = 1 ;i< m ;i++){
dp[i][0] = dp[i-1][0] + matrix[i][0];
}
for(int i = 1;i < m ;i++){
for(int j = 1 ;j< n;j++){
dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1])+matrix[i][j];
}
}
return dp[m - 1][n - 1];
}
}
求叶子节点到根节点所用的路径和
dfs然后用一个数字记录一下就可以了
import java.util.*;
public class Solution {
public int sumNumbers (TreeNode root) {
if(root == null) return 0;
return dfs(root,0);
}
int dfs(TreeNode root,int res){
if(root == null) return 0;
res = res*10 +root.val;
if(root.left == null && root.right == null) return res;
return dfs(root.left,res) + dfs(root.right,res);
}
}
二叉树到叶子节点的指定路径和
搞一个temp存起来,用target - temp =0 判断是否结束了
import java.util.*;
public class Solution {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
public ArrayList<ArrayList<Integer>> pathSum(TreeNode root, int sum) {
dfs(root,sum,new ArrayList<>());
return res;
}
void dfs(TreeNode root, int sum,ArrayList temp){
if(root == null) return;
temp.add(root.val);
if(root.left == null && root.right == null && sum == root.val) res.add(new ArrayList<>(temp));
dfs(root.left,sum - root.val,temp);
dfs(root.right,sum - root.val,temp);
temp.remove(temp.size()-1);
}
}
链表指定区域内反转
在指定区域内反转,双指针定位之后,用头插法,注意right=newhead.next
import java.util.*;
public class Solution {
public ListNode reverseBetween (ListNode head, int m, int n) {
ListNode newhead = new ListNode(0);
newhead.next = head;
ListNode left = newhead;
ListNode right = newhead.next;
for(int i = 0;i < m - 1; i++){
left = left.next;
right = right.next;
}
for(int i = 0;i < n - m;i++){
ListNode temp = right.next;
right.next = right.next.next;
temp.next = left.next;
left.next = temp;
}
return newhead.next;
}
}
合并区间
重写comparator里面的compare方法,然后通过1开始循环遍历,进行比较就可以了
import java.util.*;
public class Solution {
public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
ArrayList<Interval> res = new ArrayList<>();
if(intervals.size() == 0 || intervals == null) return res;
intervals.sort(new Comparator<Interval>(){
public int compare(Interval o1,Interval o2){
if(o1.start < o2.start){
return -1;
}else if(o1.start == o2.start){
return 0;
}else{
return 1;
}
}
});
for(int i = 1;i < intervals.size();i++){
if(intervals.get(i).start <= intervals.get(i-1).end){
intervals.get(i).start = intervals.get(i-1).start;
intervals.get(i).end = Math.max(intervals.get(i).end,intervals.get(i-1).end);
}else{
res.add(intervals.get(i-1));
}
}
res.add(intervals.get(intervals.size()-1));
return res;
}
}
判断一棵树是否为搜索二叉树和满二叉树
搜索二叉树通过dfs然后判断pre来搞定,满二叉树用队列来搞定,左右都不空就插入,左空有不空直接false,最后一个情况标记true
import java.util.*;
public class Solution {
private TreeNode pre;
public boolean[] judgeIt (TreeNode root) {
return new boolean[]{f1(root),f2(root)};
}
boolean f1(TreeNode root){
if(root == null) return true;
if(!f1(root.left)) return false;
if(pre !=null && pre.val > root.val) return false;
pre = root;
if(!f1(root.right)) return false;
return true;
}
private boolean f2(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();
boolean flag = false;
queue.offer(root);
while(!queue.isEmpty()){
TreeNode temp = queue.poll();
TreeNode left = temp.left;
TreeNode right = temp.right;
if(left != null && right != null){
if(flag) return false;
queue.offer(left);
queue.offer(right);
}else if(left == null && right != null){
return false;
}else if(left !=null){
if(flag) return false;
flag = true;
}
}
return true;
}
}
删除有序列表出现重复的元素
遇到一样的就停止,然后前面之前往后面跑,后面指针直接指向下一个就可以了
import java.util.*;
public class Solution {
public ListNode deleteDuplicates (ListNode head) {
ListNode newhead = new ListNode(0);
newhead.next = head;
ListNode pre = newhead;
ListNode cur = head;
while(cur!=null && cur.next !=null){
if(cur.val == cur.next.val){
while(cur.next!=null && cur.val == cur.next.val){
cur = cur.next;
}
pre.next = cur.next;
cur = cur.next;
}else{
pre = cur;
cur = cur.next;
}
}
return newhead.next;
}
}
矩阵元素的查找
比x小就得一列一列找,比x大,就直接加一行,因为比最大得数还大了
import java.util.*;
public class Solution {
public int[] findElement(int[][] mat, int n, int m, int x) {
int[] res = new int[2];
int row = 0,col = mat[0].length-1;
while(row < mat.length && col >=0){
if(mat[row][col] > x) col--;
else if(mat[row][col] < x) row++;
else{
res[0] = row;
res[1] = col;
break;
}
}
return res;
}
}
数组中未出现的最小整数
通过1来判断即可
import java.util.*;
public class Solution {
public int minNumberdisappered (int[] arr) {
int res = 1;
for(int data : arr){
if(res == data){
res++;
}
}
return res;
}
}
链表奇偶重排序
把后面的先领出来,最后拼接一下就可以了,过程可以画一个图
import java.util.*;
public class Solution {
public ListNode oddEvenList (ListNode head) {
if(head == null || head.next == null) return head;
ListNode afterhead = head.next;
ListNode old = head,even = head.next;
while(even!=null && even.next !=null){
old.next = even.next;
old = old.next;
even.next = old.next;
even = even.next;
}
old.next = afterhead;
return head;
}
}
括号生成
利用一个dfs轻松搞定
import java.util.*;
public class Solution {
ArrayList<String> res = new ArrayList<>();
public ArrayList<String> generateParenthesis (int n) {
String temp = "";
dfs(n,n,temp);
return res;
}
void dfs(int left,int right,String temp){
if(left == 0 && right == 0) res.add(temp);
if(left > 0) dfs(left-1,right,temp+"(");
if(left < right) dfs(left,right-1,temp+")");
}
}
顺时针旋转矩阵
直接i=j ,j=n-1-i就搞定了
import java.util.*;
public class Solution {
public int[][] rotateMatrix(int[][] mat, int n) {
int[][] res = new int[n][n];
for(int i = 0; i< n ;i++){
for(int j = 0; j < n ;j++){
res[j][n-1-i] = mat[i][j];
}
}
return res;
}
}
LRU
代码多归多,但是不难
import java.util.*;
public class Solution {
Map<Integer,Node> map = new HashMap<>();
Node head = new Node(-1,-1);
Node tail = new Node(-1,-1);
int k ;
public int[] LRU (int[][] operators, int k) {
this.k = k;
head.next = tail;
tail.prev = head;
int len = (int)Arrays.stream(operators).filter(x -> x[0]==2).count();
int[] res = new int[len];
for(int i = 0, j = 0;i <operators.length;i++){
if(operators[i][0] == 1){
set(operators[i][1],operators[i][2]);
}else{
res[j++] = get(operators[i][1]);
}
}
return res;
}
void set(int key,int val){
//这里要用本地的get方法,而不是map的get方法
if(get(key) > -1){
map.get(key).val = val;
}else{
if(k == map.size()){
int fk = tail.prev.key;
tail.prev.prev.next = tail;
tail.prev = tail.prev.prev;
map.remove(fk);
}
Node temp = new Node(key,val);
map.put(key,temp);
moveToHead(temp);
}
}
int get(int key){
if(map.containsKey(key)){
Node temp = map.get(key);
temp.next.prev = temp.prev;
temp.prev.next = temp.next;
moveToHead(temp);
return temp.val;
}
return -1;
}
void moveToHead(Node node){
node.next = head.next;
head.next.prev = node;
head.next = node;
node.prev = head;
}
static class Node{
int key,val;
Node prev,next;
public Node(int key,int val){
this.key = key;
this.val = val;
}
}
}