LeetCode之两数相加、反转链表、少箭射球、二叉树

本文分享了Java链表相加的递归解法,包括力扣LeetCode中的两个链表相加问题,以及Android中的链表反转和完全二叉树节点计数。还介绍了贪心算法的应用,如箭矢射击和砖块穿透最少。涉及数据结构、算法和Android开发技巧。
摘要由CSDN通过智能技术生成

     本文来自刘兆贤的博客_CSDN博客-Java高级,Android旅行,Android基础领域博主 ,引用必须注明出处!

 以前也有刷一些题目,但是没有记录,不方便回头看解题思路,今天开始就记录一下。

力扣刷了300题,地址:iddo - 力扣(LeetCode)

力扣

两个链表,分别纪录从个数开始的数,相加后得到新的链表

思路:递归。保留当前结点,提高连结效率。

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        return getResult(l1,l2,null,null,0);
    }

    public ListNode getResult(ListNode l1,ListNode l2,ListNode target,ListNode next,int addHigh){
        if(l1==null&&l2==null&&addHigh==0){
            return target;
        }
        int lv=0;
        int rv=0;
        if(l1!=null){
            lv=l1.val;
            l1=l1.next;
        }
        if(l2!=null){
            rv=l2.val;
            l2=l2.next;
        }
        int total=lv+rv+addHigh;
        int newVal=total;
        int newHigh=0;
        if(total>9){
            if(total==10){
                newVal=0;
            }else{
                newVal=total%10;
            }
            newHigh=1;
        }
        ListNode temp=new ListNode(newVal);
        if(target==null){
            target=temp;
        }else{
            if(next!=null){
                next.next=temp;
                next=next.next;
            }else{
                target.next=temp;
                next=target.next;
            }
        }
        return getResult(l1,l2,target,next,newHigh);
    }

执行速度还是蛮快的,内存也还好。

https://leetcode-cn.com/problems/reverse-linked-list/

反转链表

解法一:分别获得各结点,然后重新组成新的链表。重组过程:每次移动指针,将结点绑定。以此为核心思路,演化出第二种解法。

	private static ListNode reverseListNode(ListNode head) {
		List<ListNode> list = getListNodeSize(head, new ArrayList<>());
		ListNode preNode = null;
		for (int i = list.size() - 1; i > -1; i--) {
			ListNode node = list.get(i);
			// 切断结点
			node.next = null;
			if (preNode == null) {
				// 赋值初结点
				preNode = node;
			} else {
				// 临时结点
				ListNode temp = preNode.next;
				if (temp != null) {
					while (temp.next != null) {
						// 每次都将指针移到最后一个,查到最后一个结点
						temp = temp.next;
					}
					temp.next = node;
				} else {
					preNode.next = node;
				}
			}
		}
		return preNode;
	}

	private static List<ListNode> getListNodeSize(ListNode head, List<ListNode> list) {
		while (head != null) {
			list.add(head);
			return getListNodeSize(head.next, list);
		}
		return list;
	}

解法二:关键在于,使用指针结点,对新的链表进行递归赋值;演化出第三种方法。

	private static ListNode reverseListNode(ListNode head) {
		return reverseNode(head, null);
	}

	/**
	 * 
	 * @param curNode
	 *            指针结点
	 * @param headNode
	 *            新的链表
	 * @return
	 */
	private static ListNode reverseNode(ListNode curNode, ListNode headNode) {
		// 指针结点为空
		if (curNode == null) {
			return headNode;
		}
		// 新的链表
		if (headNode == null) {
			headNode = new ListNode(curNode.val);
		}
		// 指针结点
		ListNode nextNode = curNode.next;
		if (nextNode == null) {
			return headNode;
		}
		// 新链表结点
		curNode = new ListNode(nextNode.val);
		curNode.next = headNode;
		return reverseNode(nextNode, curNode);
	}

解法三:利用head结点作为基础,不断使用后续结点,充当head的父结点。

	/**
	 * 内循环算法
	 * 
	 * @param head
	 * @return
	 */
	public static ListNode reverseInnerLoop(ListNode head) {
		ListNode newNode = null;
		while (head != null) {
			// 下个结点
			ListNode nextNode = head.next;
			// 将head的下一个,指向新结点
			head.next = newNode;
			// 得到新的结点,完成反指
			newNode = head;
			// 指针结点,实现循环
			head = nextNode;
		}
		return newNode;
	}

力扣

求完全二叉树(除底层,其他层次都满)的结点个数。

思路:笨办法,递归获得

    public int countNodes(TreeNode root) {
		int count = 0;
		if (root == null) {
			return count;
		}
		count++;
		int index = 0;
		if (root.left != null) {
			count += countNodes(root.left);
		}
		if (root.right != null) {
			count += countNodes(root.right);
		}
		return count;
    }

新算法:

  public int countNodes(TreeNode root) {
		int count = 0;
		if (root == null) {
			return count;
		}
        int ld=depth(root.left);
        int rd=depth(root.right);
        //根结点
        if(ld==rd){
            int lc=1<<ld;
            System.out.println("lc:"+lc);
            return lc+countNodes(root.right);
        }
        int rc=1<<rd;
        System.out.println("rc:"+rc);
        return rc+countNodes(root.left);
    }

    public int depth(TreeNode node){
        int count=0;
        while(node!=null){
            count++;
            node=node.left;
        }
        return count;
    }

虽然使用了完全二叉树的原理,但是由于不断移位产生新的对象,耗时和内存都增加了。

力扣

贪心算法:求局部最优解。

二维空间中,x到y,给定气球坐标,全部射中需要的最少箭数。

思路:先排序,以数列首个数字从小到大排列,使用低位和高位循环匹配,不符合的需要再用一支箭头即结果+1,于是解出此题。

	public static int findMinArrowShots(int[][] points) {
		if (points.length == 0) {
			return 0;
		}
		// 从大到小排序
		Arrays.sort(points, new Comparator<int[]>() {

			@Override
			public int compare(int[] o1, int[] o2) {
				return o1[0] - o2[0];
			}
		});
		// 检查
		int low = points[0][0];
		int high = points[0][1];
		int result = 1;
		for (int aIndex = 1; aIndex < points.length; aIndex++) {
			int[] bttr = points[aIndex];
			if (bttr[0] >= low && bttr[0] <= high) {
				// 默认低位和高位,后面逐步缩小范围,最后囊括所有数据
				if (bttr[0] > low) {
					low = bttr[0];
				}
				if (bttr[1] < high) {
					high = bttr[1];
				}
				continue;
			} else {
				// 不符合,则使用新箭
				low = points[aIndex][0];
				high = points[aIndex][1];
			}
			result++;
		}
		return result;
	}

力扣

又是贪心算法,求穿墙最少,需要几条垂线

    public int leastBricks(List<List<Integer>> wall) {
        //注意,使用按key排序的map集合,将所有的值,和出现的次数保存起来
        Map<Integer,Integer> map=new TreeMap();
        //找出值最大的key
        int maxKey=0;
        for(List<Integer> sec:wall){
            int key=0;
            for(Integer value:sec){
                key+=value;
                Integer num=map.get(key);
                if(key>maxKey){
                    maxKey=key;
                }
                if(num==null){
                    map.put(key,1);
                }else{
                    map.put(key,num+1);
                }
            }
        }
        int nums=0;
        int mostValue=0;
        Iterator<Integer> iterator=map.keySet().iterator();
        while(iterator.hasNext()){
            Integer key=iterator.next();
            Integer val=map.get(key);
            if(val>=nums&&key<maxKey){
                //找到数量最多的,同时小于最大key,以防穿墙
                nums=val;
                //它的索引
                mostValue=key;
            }
        }
        System.out.print(mostValue);
        int count=0;
        for(List<Integer> sec:wall){
            int total=0;
            boolean exist=false;
            for(Integer se:sec){
                total+=se;
                if(total==mostValue){
                    //说明穿过缝隙
                    exist=true;
                    continue;
                }else if(total>mostValue){
                    //说明已经超过缝隙
                    continue;
                }
            }
            if(!exist){
                count++;
            }
        }
        return count;
    }

算法不够高明,但思路还算清晰。

二叉树,根据中序和后序,求原树。

中序:左根右

后序:左右根

前序:根左右
 

/**
 * 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 TreeNode buildTree(int[] inorder, int[] postorder) {
        //后序的最后一个肯定是根结点,根据此定律,做递归
        if(inorder.length==0){
            return null;
        }
        int iLen=inorder.length,pLen=postorder.length,val=postorder[pLen-1];
        TreeNode root=new TreeNode(val);
        for(int i=0;i<iLen;i++){
            if(inorder[i]==val){
                int[] in_left=Arrays.copyOfRange(inorder,0,i);
                int[] in_right=Arrays.copyOfRange(inorder,i+1,iLen);
                int[] post_left=Arrays.copyOfRange(postorder,0,i);
                int[] post_right=Arrays.copyOfRange(postorder,i,pLen-1);
                root.left=buildTree(in_left,post_left);
                root.right=buildTree(in_right,post_right);
                break;
            }
        }
        return root;
    }
}

遍历:所有数据都访问到,且只访问一次。

求质数小技巧:最大质数小于等于值的平方根。

TreeMap,key自动排序的Map;TreeSet,值自动排序的List。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘兆贤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值