LeetcodePracticeJava(一)hotcode_rank100_easy

LeetcodePracticeJava(一)hotcode_rank100_easy

算法orTips记录

SumUpOfTwoNumbers001

在这里插入图片描述

import java.util.HashMap;
import java.util.Map;

class Solution {
public static int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> map = new HashMap<>();
//新建hashmap
//HashMap<Integer,Integer>类型名,两个变量为整形
//map为变量名,new为动态申请
        int[] result = new int[2];
//用于保存结果,长度为2的数组
        for (int i = 0; i <nums.length ; i++) {
//一次循环,时间复杂度O(n)
            if(map.containsKey(nums[i])){
//判断条件:输入中的第i个,作为键,在map中有对应的值
//map.containsKey()返回true or false,代表在map中是否有key存在
                result[0] = map.get(nums[i]);
//很明显,put是存,get是取,既返回键对应的值,get到的是对于num[i]的目标值所在的位置
                result[1] = i;
//i是当前已知值的位置
                return result;
            }
            map.put(target-nums[i],i);
 //存入的键值对  目标值:已知值的位置,这个很关键,虽然coding时思维多一圈,但是加速了程序
 //也可以理解成  已知值:目标值的位置,这个操作有点意思
 //Map.put() 方法将获取 Map 集合的所有键名,并存放在一个 Set 集合对象中;存入
        }
        return result;
    }
}

破题要点:
哈希表,对撞
键值对,把位置序号 i 作为值来存放
多想一层,补数的概念

mark:
这样只能输出一组答案

EffectiveBrackets020

在这里插入图片描述

使用栈的进出判断(low)

public class Solution {
 
	public boolean isValid(String s) {
		Stack<Character> stack = new Stack<>();
//Character 类用于对单个字符进行操作。
//Character 类在对象中包装一个基本类型 char 的值
		for(int i = 0; i < s.length(); i++) {
			Character character1 = s.charAt(i);
			if(character1 == '(' || character1 == '[' || character1 == '{') {
				stack.push(character1);
			}else if(character1 == ')') {
				if(stack.isEmpty()) {
					return false;
				}
				Character character2 = stack.pop();
				if(character2 != '(') {
					return false;
				}
			}else if(character1 == ']') {
				if(stack.isEmpty()) {
					return false;
				}
				Character character2 = stack.pop();
				if(character2 != '[') {
					return false;
				}
			}else if(character1 == '}') {
				if(stack.isEmpty()) {
					return false;
				}
				Character character2 = stack.pop();
				if(character2 != '{') {
					return false;
				}
			}
		}
		return stack.isEmpty();
	}
}
基于字符翻译或大小的逻辑判断

待完善
[ 的下一位只能是( or ]
( 28
) 29
[ 91
] 93
{ 123
} 125
用哈希表,键值对,分别赋值123456
那么原string就变成了一个数组
eg:()]]{{[()]}>12445531246
so 从数字逻辑上,1后面只能是2,3后面只能是1.4,5后面只能是1.3.6
and 2前面必须是1,4前面必须是2.3,6前面必须是2.4.5

package hotcode_rank100;

import java.util.HashMap;

public class EffectiveBrackets020 {
    public static void main(String[] args) {
        System.out.println( isValid (")"));
    }
    public static boolean isValid(String s) {
        HashMap<Character, Integer> map = new HashMap<>();
        map.put('(', 1);
        map.put(')', 2);
        map.put('[', 3);
        map.put(']', 4);
        map.put('{', 5);
        map.put('}', 6);

        int l = s.length();
        int []arr = new int[ l+1 ];
        for (int j = 0; j < l; j++){
            arr[j] = map.get(s.charAt(j));
            arr[j+1]=0;
            }
        int i = 0;
        while (i<l) {
            if (arr[i] % 2 == 1 || i==0) {
                if (arr[i + 1] == arr[i] + 1 || arr[i + 1] == arr[i] - 2 || arr[i + 1] == arr[i] - 4) {
                    i++;
                } else {
                    return false;
                }
            }
            else {
                if (arr[i - 1] == arr[i] - 1 || arr[i - 1] == arr[i] - 2 || arr[i - 1] == arr[i] - 4) {
                    i++;
                } else {
                    return false;
                }
            }
        }
    return true;
    }
}

弃了,判断条件和字符转换过于复杂;由于涉及太多的arr[i+1]、arr[i-1],在Java中并不好处理,还是乖乖用栈解决吧

利用ascll码进行判断
class Solution {
public:
    bool isValid(string s) {
	int j = 0;
	string temp;
	int len = s.size();
	temp += s[0];
 
	if (s[0] == '(' || s[0] == '[' || s[0] == '{'){
		for (int i = 1;i < len;i++){
			if ((s[i] == temp[j] + 1) || (s[i] == temp[j] + 2)){
				temp.erase (temp.end()-1);
				j--;
			}
			else {
				temp += s[i];
				j++;
			}
		}
		if (temp.empty())
			return true;
		else return false;
			
	}
	else{
	if (s  == "")
		return true;
	else return false;
	}
        
	}
};
使用栈的最快解法
package hotcode_rank100;
import java.util.Stack;

public class EffectiveBrackets020_2 {
    public static void main(String[] args) {
        System.out.println(isValid("{[()]"));
    }
    public static boolean isValid(String s) {
        Stack<Character> stack = new Stack<Character>();
        for (char c : s.toCharArray()) {
            if (c == '(')
                stack.push(')');
            else if (c == '{')
                stack.push('}');
            else if (c == '[')
                stack.push(']');
            else if (stack.isEmpty() || stack.pop() != c)
                return false;
        }
        return stack.isEmpty();
    }
}

还是之前的大哥,往栈里输入的是补数!!
然后取出来和c比较就行了,简单快捷,目前来说发现的行数最少的代码
栈的特性,先进后出,正好匹配到三级括号的需求

Stack<Character> stack = new Stack<Character>();
stack.push()//入栈
stack.pop()//出栈
//强调出入顺序的问题

MergeOrderedList021

在这里插入图片描述
可以使用,递归或者迭代
实现归并排序的子过程
归并排序
是创建在归并操作上的一种有效的排序算法。采用分治法,各层分治递归可以同时进行。
归并排序思路简单,速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。

迭代法

代码冗余问题,cur1 cur2没太必要?直接对l1 l2操作即可
https://www.cnblogs.com/easyidea/p/13371863.html

public class Solution {
 
	public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//三个指针,分别指向L1、L2、dummyHead的头结点
		ListNode cur1 = l1;
		ListNode cur2 = l2;
		ListNode dummyHead = new ListNode(0);
//为新的链表设置虚拟头结点,节点值为0(anyway输出的时候也不管他)
		ListNode cur = dummyHead;
//在两个链表任一不为空的情况下,执行循环
		while(cur1 != null || cur2 != null) {
			if(cur1 == null) {
				cur.next = cur2;//若L1空了,则将L2接在结果后(指针cur2连接cur.next>cur2.next)
				cur2 = cur2.next;
			}else if(cur2 == null) {
				cur.next = cur1;//若L2空了,则将L1接在结果后(指针cur1连接cur.next>cur1.next)
				cur1 = cur1.next;
			}else if(cur1 != null && cur2 != null) {
//当cur1 cur2都不空
				if(cur1.val > cur2.val) {
					cur.next = cur2;//将cur2的当前值给到cur.next
					cur2 = cur2.next;//将指针cur2,向后一位,也就形成了遍历
				}else {
					cur.next = cur1;
					cur1 = cur1.next;
				}
			}
			cur = cur.next;//将上面if中得到的cur.next接到cur后面,然后继续循环
		}
		return dummyHead.next;//返回头结点之后的部分
	}
}
递归法
public class Solution {
 
	public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
		if(l1 == null) {
			return l2;
		}
		if(l2 == null) {
			return l1;
		}
		if(l1.val > l2.val) {//如果l2小,那么这个值在前面,所以接下来需要合并的链表就是l1和l2.next
			l2.next = mergeTwoLists(l1, l2.next);//标准递归,调用自己
			return l2;
		}else {
			l1.next = mergeTwoLists(l1.next, l2);//当l1的值小于等于l2的值时,我们令l1指向合并好l1.next和l2的结果,并返回l1
			return l1;
//也就是说最后,l1和l2,一个为空,一个为合并好的结果
//合并结果在l1.next和l2.next前反复横跳
		}
	}
}

MaxSubArray053

在这里插入图片描述

有推荐用分治算法待研究
我的想法:
从第一个位置开始,判断正负零,[0]+[1],大于0则继续向后加,当sum<=0时,直接跳到下一个位置
判断正负零时,正开始计算,零负跳过当前位置
需要一个sum保存历史最大值,一个sum1保存实时计算结果
当sum1>sum,更新sum
当某个位置的值大于sum,更新(这其实是上述条件的特殊情况,不用单独语句实现)

package hotcode_rank100;

public class MaxSubArray053 {
    public static void main(String[] args) {
        int[] nums = {-2,1,-3,4,-1,2,1,-5,4};
        System.out.println(maxSubArray(nums));//
        System.out.println(maxSubArray2(nums));//分治算法
    }

    public static int maxSubArray(int[] nums) {
        // dp[i] 表示以nums[i]结尾的最大和
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int res = dp[0];
        for (int i = 1; i <nums.length ; i++) {
            dp[i] = dp[i-1]>0 ? dp[i-1]+nums[i] : nums[i];
 //?为三元运算符,若前式成立,返回冒号左侧值,这一行为关键逻辑,这种写法足够简单
 //思路为,建立一个数组,来记录过程中产生的历史sum,便于下一次循环时取出来比较
 //利用一个整型变量,一个if语句,配合continue也可以实现
            res = Math.max(res,dp[i]);
        }
        return res;
    }

    public static int maxSubArray2(int[] nums) {
        return DivideConquer(nums,0,nums.length-1);
    }

    public static int DivideConquer(int[] nums, int start, int end){
        if(start == end)
            return nums[start];
        else{
            int mid = (start+end)/2;
            int left = DivideConquer(nums, start, mid);
            int right = DivideConquer(nums, mid+1, end);
            int temp = 0;
            int lmax = nums[mid];
            for (int i = mid; i >=start ; i--) {
                temp += nums[i];
                lmax = Math.max(temp,lmax);
            }
            temp = 0;
            int rmax = nums[mid+1];
            for (int i = mid+1; i <= end ; i++) {
                temp += nums[i];
                rmax = Math.max(temp,rmax);
            }
            return Math.max(Math.max(left,right),lmax+rmax);
        }
    }
//在线算法,很巧的是和我之前的想法很像
    public int maxSubArray3(int[] nums) {
		int n = nums.length;
		int result = Integer.MIN_VALUE;
//初始化result,为能去得的最小数,防止越界,看起来很唬人,但只要比最大和小,就不会有bug,但这样更保险
		int sum = 0;
		for (int i = 0; i < n; i++) {
			sum += nums[i];
			result = Math.max(result, sum);
			if(sum < 0) {
				sum = 0;
//精华所在,置零代表着上一个子序列,不参与考虑了,只要result还在,从下一个元素重新从头考虑就行了
			}
		}
		return result;
    }
}

ClimbStairs070

在这里插入图片描述

public class lc70 {
    public static void main(String[] args) {
        System.out.println(climbStairs(3));
    }
    public static int climbStairs(int n) {
        int[] re = new int[n+1];
//n个有效值,这样是为了让n级台阶和re[n]相对应
        re[0] = 1;
        re[1] = 1;
        for (int i = 2; i <= n ; i++ ){
            re[i] = re[i-1] + re[i-2];
//在面对n级台阶时,先迈一步,当前step跨1级,则剩余走法re[n-1]
//同理,当前step跨越2级,则剩余走法re[n-2]
        }
        return re[n];
	}
}

IsSymmetric101

在这里插入图片描述

public class IsSymmetric101 {
    public static void main(String[] args) {
        //
    }
    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) { val = x; }
    }
//从这里开始是有用的代码,大佬的思路和写法都太强了
//唯一的就是,如果用行数衡量工作量,这样岂不是很吃亏[滑稽]
    public boolean isSymmetric(TreeNode root) {
//构造函数,输入树的根节点    
        return root==null || func(root.left, root.right);
//根为空or根的左右子树满足条件,为true,进入递归判断func
    }
//条件功能func,输入左右子树
    public static boolean func(TreeNode left, TreeNode right){
        if(left==null || right==null)
        //如果左树or右树为空,则判断是否相等,返回true、false
            return left == right;
        //在左右都不为空的情况下,有以下三个必须同时成立的条件
        //左右树的值相等且左左和右右、左右和右左满足func成立条件(递归调用自己)
        return (left.val==right.val) && func(left.left,right.right) && func(left.right,right.left);
    }
}

maxDepth104

在这里插入图片描述

public class lc104 {
    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) { val = x; }
    }
//递归,超简单
    public int maxDepth(TreeNode root) {
        if(root==null) return 0;
        return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
    }
}

MaxProfit121

在这里插入图片描述
低价策略

    public int maxProfit(int[] prices) {
    //初始化,最小值为max,防止越界,res置零
        int min = Integer.MAX_VALUE, res=0;
    //遍历所有位置的价格
        for(int i=0; i<prices.length; i++){
            min = Math.min(min, prices[i]);//在当前价格和历史低价中寻找小值作为买入点
            res = Math.max(res, prices[i]-min);
//当前价格与历史低价的差,作为假设利润,与之前的假设利润比较,取其中大值作为最后的maxprofit
        }
        return res;
    }

动态规划

public class Solution {
    public int maxProfit(int[] prices) {
        int result = 0;
        if(prices.length == 0){
            return result;
        }
//新建一个数组 0到len-1
        int[] dp = new int[prices.length];
        dp[0] = Integer.MAX_VALUE;
//对于每一个i天,当天价格prices[i-1],今天之前的历史低价dp[i-1]
        for(int i = 1; i < dp.length; i++){
            if(prices[i - 1] < dp[i - 1]){
                dp[i] = prices[i - 1];
            }else{
//若今天的价格高于历史价格,那么今天的历史低价,和前一天一样
                dp[i] = dp[i - 1];
            }
        }
        for(int i = 1; i < dp.length; i++){
//顺序拿出历史低价,用今日价格减历史低价,得到利润,re寻找其中最大值
//因为第一天不能又买又卖,所以不用考虑i=0,i=1代表第二天,i=len-1代表最后一天
//如果使用i-1,在第一天时,if不成立,只要把循环条件改成<=,i=len时,访问位置i-1,也是没有错的
            if(prices[i] - dp[i] > result){
                result = prices[i] - dp[i];
            }
        }
        return result;
    }
}

SingleNumber136

在这里插入图片描述
思路1:栈?类似括号那题
思路2:按位异或

    public static int singleNumber(int[] nums) {
        int res = nums[0];
        for (int i = 1; i < nums.length ; i++) {
            res = res ^ nums[i];
  //二进制的按位异或。
        }
        return res;
    }

HasCycle141

在这里插入图片描述

哈希表

在遍历的过程中,将每个节点存入HashSet,如果发现已遍历点证明有环

public class Solution1 {
    public boolean hasCycle(ListNode head) {
        HashSet<ListNode> hashSet = new HashSet<>();
//声明HashSet,类型为ListNode
        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;
        ListNode cur = dummyHead;
//指针定位在虚拟头,下一位是head链表
        while(null != cur.next){
            if(hashSet.contains(cur.next)){
                return true;
            }
//如果hashSet中含有cur.next,证明有环;否则更新指针,并把更新后的节点存入hashSet
            cur = cur.next;
            hashSet.add(cur);
        }
        return false;
    }
}
双指针

两个指针同时开始遍历链表,一个快一个慢,如果快的追上了慢的,证明套圈了,有环

public class Solution {
    public boolean hasCycle(ListNode head) {
//声明两个指针,都指向虚拟头
        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;
        ListNode cur1 = dummyHead;
        ListNode cur2 = dummyHead;
        while(true){
            if(null == cur2.next || null == cur2.next.next){
//循环条件,两个指针的下一位不为空,有一个为空则返回false
                return false;
            }
            cur1 = cur1.next;
//慢指针,一次一步
            cur2 = cur2.next.next;
//快指针,一次两步
            if(cur1 == cur2){
                return true;
            }
        }
    }
}

MinStack155

思路:借助一个其他的容器,辅助记录栈中最小值(可以是一个int数,也可以是一个栈)
(如果用一个栈,不断push,始终保证pop是最小值,岂不快活)
一开始没能考虑到取出pop后Min的变化,所以stackMIn中需要记录历史最小值
注意pop和peek的区别

class MinStack{
	private Stack<Integer> stackData;
	private Stack<Integer> stackMin;
	
	public MinStack(){
		stackData = new Stack<Integer>();
		stackMin = new Stack<Integer>();
	}

	public void push(int x){
		if(stackMin.empty()||x <= getMin()){
			stackMin.push(x);
		}
		else {
            int newMin = getMin();
            stackMin.push(newMin);
//保留历史最小值,当pop取出min变化时,从这里拿到
        }
		stackData.push(x);
	}
	public void pop() {
        if(stackData.empty()) {
            throw new RuntimeException("your stack is empty!");
        }
        stackData.pop();
        stackMin.pop();//关键代码,在取出pop时,有可能Min发生了变化
    }

    public int top() {
        if(stackData.empty()) {
            throw new RuntimeException("your stack is empty!");
        }
        return stackData.peek();
    }

    public int getMin() {
        if(stackMin.empty()) {
            throw new RuntimeException("your stack is empty!");
        }
        return stackMin.peek();
    }
}

GetIntersectionNode160

思路:设置两个指针,从头到尾,获得两个链表长度
巧妙点:长度做差,得到一个差值,让长链表的指针先移动差值个位数
然后二者同频,直到发现某个点两个指针等值,这就找到了交点
如果一直没有发现则返回null,证明没有交点

public class Solution{
	public ListNode getIntersectionNode(ListNode headA, ListNode headB){
		int lenA = getLength(headA);
		int lenB = getLength(headB);
		ListNode curA = headA;
		ListNode curB = headB;
		int gap = Math.abs(lenA -lenB);

		
        if (lenA >= lenB) {
            while(gap-- > 0){
                curA = curA.next;
            }
        } else {
            while(gap-- > 0){
                curB = curB.next;
            }
        }

		while (null!=curA){
			if(curA==curB){
			return curA;}
			curA = curA.next;
			curB = curB.next;
		}
		return null;
	}
//设计了一个private函数实现计算长度的功能	
	private int getLength(ListNode head){
		int len = 0;
		ListNode cur = head;
		while(null != cur){
			cur = cur.next;
			len++;
		}
	}
}

MajorityElement169

在这里插入图片描述

思路1:hashmap,用哈希表对应保存元素和出现次数,第二个循环找出出现次数最多的元素
思路2:排序法,先排序,然后输出第n/2个元素作为结果
思路3:巧解

public static int majorityElement(int[] nums) {
        int num = nums[0], count = 1;
        for(int i=1;i<nums.length;i++){
//从第2个数开始,判断和第一个数是否一样        
            if(nums[i] == num) {
                count++;
            } else if(--count < 0) {
//当发现count被扣到0,就重新开始计数(众数总会在一个区域取得绝对优势,题中说多于n/2次)
                num = nums[i];
                count = 1;
            }
        }
        return num;
    }

ReserveList206

在这里插入图片描述
一般来说,树递归,线性迭代,这样用的多一点,但并不绝对

递归

思路:链表翻转equals翻转除头结点外的链表,再将头结点接在最后

public class Solution {
	
	public ListNode reverseList(ListNode head) {
//递归结束条件头结点自身为null或指向null(一会儿测试下不考虑自身为空的情况)
		if(head == null || head.next == null) {
			return head;
		}
//实际上reverse没有进行翻转操作,只需要将头结点接在子链表的后面,再对子链表调用这个函数就可以了
		ListNode newHead = reverseList(head.next);
		head.next.next = head;
//原头结点接在子链表的后面(关键操作)子链表在递归语句中,从return中获得
		head.next = null;
//原头的下一位指向null,也就是将现在的尾结点指向null
		return newHead;
	}
}
迭代

思路:借助三个指针,作为中间量

if(head == null || head.next==null) return head;
	ListNode p = head;
	ListNode q = head.next;
	ListNode m;
	p.next = null;
	while(q!=null){
		m = q.next;//记录一下q后面是什么鬼
		q.next = p;//把p放在q后面,p是之前的头
		p = q;//q放在头位置了
		q = m;//更新一下,对于下一个循环,q=q.next
	}
	return p;

Invertree226

在这里插入图片描述
思路:迭代,循环while(当前node的子节点不为null),从底层开始左右子节点交换(应该需要一个中间量)

if (null == root){
	return root;}

TreeNode leftChild = invertTree(root.right);
TreeNode rightChild = invertTree(root.left);
root.left = leftChild;
root.right = rightChild;
//这里用了两个中间量,为了让代码更好看
return root;

设立二叉树的输入!

public class Solution {
	Scanner scanner = new Scanner(System.in);
	
	// 建立二叉树
	public TreeNode createTree(TreeNode root) {
		String val;
		val = scanner.next(); // next方法每次取到一个间隔符前面的数据
		if(val.equals("#")) {
			return null;
		}
		root = new TreeNode(Integer.parseInt(val));//  System.out.println("输入的数据为:" + val);
		root.left = createTree(root.left);
		root.right = createTree(root.right);
		return root;
	}
	// 得到二叉树的镜像  —— 递归的方式
    public void Mirror(TreeNode root) {
    	if(root == null) {
    		return;
    	}
    	if((root.left == null) && (root.right == null)) {
    		return;
    	}
    	TreeNode temp = root.left;
    	root.left = root.right;
    	root.right = temp;
    	Mirror(root.left);
    	Mirror(root.right);
    }
     // 得到二叉树的镜像 —— 不使用递归
    public void MirrorNotRecursive(TreeNode root) {
        java.util.LinkedList<TreeNode> queue = new java.util.LinkedList<TreeNode>();
        TreeNode temp = null;
        if(root == null) {
            return;
        }
        queue.add(root);
        while(queue.size() != 0) {
            TreeNode node = queue.removeFirst();
            temp = node.left;
            node.left = node.right;
            node.right = temp;
            if(node.right != null) {
                queue.add(node.right);  // 入队的为原来的左孩子
            }
            if(node.left != null) {
                queue.add(node.left);
            }
        }
    }
    
    // 层次遍历二叉树
    public void levelTraverse(TreeNode root) {
     	if (root == null) {
    		 return;
     	}
    	 LinkedList<TreeNode> list = new LinkedList<TreeNode>();
    	 list.add(root);
    	 while (list.size() != 0) {
     		TreeNode node = list.removeFirst(); // list.removeFirst() 该方法LinkedList才有
    		System.out.print(node.val + " ");
     		if(node.left != null) {
    			 list.add(node.left);  // list.add()添加单个元素,如果不指定索引的话,元素将被添加到链表的最后
    		}
    		if(node.right != null) {
    			list.add(node.right);
    		}
    	}
    }
    
    public static void main(String[] args) {
    	Solution solution = new Solution();
    	TreeNode root = null;
    	root = solution.createTree(root);
    	System.out.println("原二叉树的层次遍历");
    	solution.levelTraverse(root);
    	solution.Mirror(root);
    	System.out.println("\n输出该二叉树的镜像");
    	solution.levelTraverse(root);
    	solution.MirrorNotRecursive(root);
    	System.out.println("\n输出该二叉树的镜像(非递归方式)");
    	solution.levelTraverse(root);
    }
}
 
/*
 * 测试数据:
 * 1 2 3 # 4 # # 5 6 # # # 7 8 # # 9 10 # # 11 # #  (说明:其中#说明左右子树为空)
 * 用先序遍历来建立树后,层次遍历结果为: 1 2 7 3 5 8 9 4 6 10 11
 * 反转二叉树之后:1 7 2 9 8 5 3 11 10 6 4 
 */

IsPalindrome234

在这里插入图片描述
思路1:全部写入数组,判断数组是否回文
思路2:快慢指针找到中点,将后半部分翻转,逐位判断是否相同

//思路2
public class solution{
	public boolean isPalindrome(ListNode head){
		if (head == null || head.next == null){
			return true;}
		ListNode middle = partition(head);
		middle = reverseList(middle);
		while (head != null && middle != null){
			if (head.val != middle.val){
				return false;}
			head = head.next;
			middle = middle.next;
		}
		return true;
	}
	private ListNode partition(ListNode head){
		ListNode fast = head;
		ListNode slow = head;
		while (fast != null && fast.next != null){
			fast = fast.next.next;
			slow = slow.next;}
		return slow;
	} 
	private ListNode reverseList(ListNode head){
		if (head == null || head.next == null){
			return head;}
		ListNode p = head;
		ListNode q = head.next;
		ListNode m = null;
		p.next = null;
		while (q!=null){
			m = q.next;
			q.next = p;
			p = q;
			q = m;}
		return p;//p才是头啊臭宝!!p是头,只不过值不是一开始的head的值了
	}
}

MoveZeros283

在这里插入图片描述
思路1:使用一个额外的数组,初始化均为0,对原数组中所有非零元素进行复制(但是这样不符合说明1)
思路2:使用k记录遇到零的次数,遇到k次后,则对后续元素向前移动k个位置
思路3:对数组中每个元素,不断的交换非0元素和0元素之间的位置

class Solution:
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        k = 0
        for i, num in enumerate(nums):
            if num != 0:
            #在这加一句 if num != k:进行优化,参考摩尔算法
                nums[i], nums[k] = nums[k], nums[i]
                k += 1
class Solution {
    public void moveZeroes(int[] nums) {
        int k=0;
        int temp = 0;
        for(int i = 0; i < nums.length; i++){
			if (nums[i] != 0){
				temp = nums[i];
				nums[i] = nums[k];
				nums[k] = temp;
				k++;
			}
    	}
    }
}

FindDisappearedNumbers448

在这里插入图片描述

思路:以值的正负,来代表该值索引的数字是否已经出现过(索引注意加减1)

        List<Integer> results = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {
            if (nums[Math.abs(nums[i]) - 1] > 0) {
                nums[Math.abs(nums[i]) - 1] = - nums[Math.abs(nums[i]) - 1];
//Math.abs(nums[i])-1位置上的值,代表了Math.abs(nums[i])有没有出现过
//绝对值还在,不影响后续遍历,但正负号已经写入了
            }
        }
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) {
//i位置上的正负,代表了i+1这个数字是否出现过
                results.add(i + 1);
            }
        }
        return results;

HanmingDistance461

在这里插入图片描述
思路:异或,数1

//异或操作得到101
    int z = x ^ y;
	int sum = 0;
	while (z!=0){
		sum += z & 1;
//按位与运算 101 & 001 = 001
		z = z>>1;
//右移运算是将一个二进制位的操作数按指定移动的位数向右移动,移出位被丢弃
	}
	return sum;
//根据循环,z=101,sum=1,z=10,10&01=00,sum=1,z=1,1&1=1,sum=2,z=0

DiameterOfBinaryTree543

在这里插入图片描述
思路:对左右子树求最大直径,然后加和(循环条件该节点有子节点)
key:直径有可能不经过根节点
递归

public class Solution {
    int maxLen =0;
    public int diameterOfBinaryTree(TreeNode root) {
        pathLen(root);
        return maxLen;
//最后我们要的是最长路径返回的是maxLen中保存的最大值
    }

    public int pathLen(TreeNode root){
        if(root==null){
            return 0;
        }
        int left = pathLen(root.left);
        int right = pathLen(root.right);
        maxLen = Math.max(maxLen, left+right);
        return Math.max(left+1, right+1);
//这个return回去给pathLen的,所以要返回子节点中的最长路径
    }
}

MergeTrees617

在这里插入图片描述
思路:简单递归,但前提要处理好root1、root2中null的问题,对于每次合并,都先合并根节点,然后递归合并子树

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if (root1 == null){
            return root2;
        }
        if (root2 == null){
            return root1;
        }
        root1.val = root1.val + root2.val;
        root1.left = mergeTrees(root1.left,root2.left);
        root1.right = mergeTrees(root1.right,root2.right);
        return root1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值