算法
Posted xiangkejin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法相关的知识,希望对你有一定的参考价值。
36.两个链表的第一个公共节点
题目描述
输入两个链表,找出它们的第一个公共结点。
1.具有重合节点的两个链表是一个Y字性,用两个堆栈放这两个链表,从尾部开始遍历,直到遍历到最后一个重合节点。
这种算法时间复杂度为O(m+n),但是空间复杂度也是O(m+n),相当于是空间换时间
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ import java.util.*; public class Solution { public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { Stack<ListNode> s1=new Stack<ListNode>(); Stack<ListNode> s2=new Stack<ListNode>(); while(pHead1!=null){ s1.add(pHead1); pHead1=pHead1.next; } while(pHead2!=null){ s2.add(pHead2); pHead2=pHead2.next; } ListNode foundNode =null; ListNode node =null; while(!s1.isEmpty() && !s2.isEmpty()){ node=s1.pop(); if(node==s2.pop()) foundNode =node; else return foundNode; } return foundNode; } }
2.利用hashmap的key不能重复的原理,首先遍历一个链表进行存放,然后遍历另外一个链表,找到第一个与map中key相同的节点。
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ import java.util.HashMap; public class Solution { public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { ListNode current1 = pHead1; ListNode current2 = pHead2; HashMap<ListNode, Integer> hashMap = new HashMap<ListNode, Integer>(); while (current1 != null) { hashMap.put(current1, null); current1 = current1.next; } while (current2 != null) { if (hashMap.containsKey(current2)) return current2; current2 = current2.next; } return null; } }
3.首先遍历两个链表得到它们的长度,就能知道哪个链表比较长,以及长的链表比短的链表多几个节点。第二次遍历的时候,在较长的链表上线走若干步,接着同时在两个链表上遍历,找到的第一个相同的节点就是它们的第一个公共节点。
链接:https://www.nowcoder.com/questionTerminal/6ab1d9a29e88450685099d45c9e31e46 来源:牛客网 public ListNode FindFirstCommonNodeII(ListNode pHead1, ListNode pHead2) { ListNode current1 = pHead1;// 链表1 ListNode current2 = pHead2;// 链表2 if (pHead1 == null || pHead2 == null) return null; int length1 = getLength(current1); int length2 = getLength(current2); // 两连表的长度差 // 如果链表1的长度大于链表2的长度 if (length1 >= length2) { int len = length1 - length2; // 先遍历链表1,遍历的长度就是两链表的长度差 while (len > 0) { current1 = current1.next; len--; } } // 如果链表2的长度大于链表1的长度 else if (length1 < length2) { int len = length2 - length1; // 先遍历链表1,遍历的长度就是两链表的长度差 while (len > 0) { current2 = current2.next; len--; } } //开始齐头并进,直到找到第一个公共结点 while(current1!=current2){ current1=current1.next; current2=current2.next; } return current1; } // 求指定链表的长度 public static int getLength(ListNode pHead) { int length = 0; ListNode current = pHead; while (current != null) { length++; current = current.next; } return length; }
37.数字在排序数组中出现的次数
题目描述
统计一个数字在排序数组中出现的次数。
注意是在排序后的数组中,遍历数组找到目标数字,当遍历到和目标数字不相等的位置后就可以不再遍历,减小时间复杂度。
public class Solution { public int GetNumberOfK(int [] array , int k) { int number = 0; int flag = 0; for(int i: array){ if(i == k){ number++; flag = 1; }else if(i != k && flag == 1){ return number; } } return number; } }
二分法:
public class Solution { public int GetNumberOfK(int [] array , int k) { int length = array.length; if(length == 0){ return 0; } int firstK = getFirstK(array, k, 0, length-1); int lastK = getLastK(array, k, 0, length-1); if(firstK != -1 && lastK != -1){ return lastK - firstK + 1; } return 0; } //递归写法 private int getFirstK(int [] array , int k, int start, int end){ if(start > end){ return -1; } int mid = (start + end) >> 1; if(array[mid] > k){ return getFirstK(array, k, start, mid-1); }else if (array[mid] < k){ return getFirstK(array, k, mid+1, end); }else if(mid-1 >=0 && array[mid-1] == k){ return getFirstK(array, k, start, mid-1); }else{ return mid; } } //循环写法 private int getLastK(int [] array , int k, int start, int end){ int length = array.length; int mid = (start + end) >> 1; while(start <= end){ if(array[mid] > k){ end = mid-1; }else if(array[mid] < k){ start = mid+1; }else if(mid+1 < length && array[mid+1] == k){ start = mid+1; }else{ return mid; } mid = (start + end) >> 1; } return -1; } }
38.二叉树的深度
题目描述
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
1.采用递归方法
/** public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } */ public class Solution { public int TreeDepth(TreeNode root) { if(root == null) return 0; int left = TreeDepth(root.left); int right = TreeDepth(root.right); return (left>right)?(left+1):(right+1); } }
2.采用层次遍历的方式
先知道下一层树的个数,然后count++,相等时候,结束一层的层序遍历。
链接:https://www.nowcoder.com/questionTerminal/435fb86331474282a3499955f0a41e8b 来源:牛客网 import java.util.Queue; import java.util.LinkedList; public class Solution { public int TreeDepth(TreeNode pRoot) { if(pRoot == null){ return 0; } Queue<TreeNode> queue = new LinkedList<TreeNode>(); queue.add(pRoot); int depth = 0, count = 0, nextCount = 1; while(queue.size()!=0){ TreeNode top = queue.poll(); count++; if(top.left != null){ queue.add(top.left); } if(top.right != null){ queue.add(top.right); } if(count == nextCount){ nextCount = queue.size(); count = 0; depth++; } } return depth; } }
39.平衡二叉树
题目描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
平衡二叉树左右树的高度不超过1。
递归获取树的高度
public class Solution { private boolean isBalanced = true; public boolean IsBalanced_Solution(TreeNode root) { height(root); return isBalanced; } private int height(TreeNode root){ if(root == null) return 0; int left = height(root.left); int right = height(root.right); if(Math.abs(left-right)>1) isBalanced = false; return 1+Math.max(left,right); } }
40.数组中只出现一次的数字
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
思路:
//使用堆栈来做辅助功能,将数组先排序,依次入栈,每一次数组入栈时和当前堆栈的栈头比较,如果当前堆栈为空,就入栈,如果和当前栈头的元素相同就出栈,当数组中左右元素都入栈完毕,那么当前栈中剩余的2个元素就是只出现一次的两个元素
时间复杂度为O(n2),空间复杂度为O(n)
//num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 import java.util.*; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { Arrays.sort(array); Stack<Integer> stack = new Stack<Integer>(); int len = array.length; if(array == null){ num1[0] = 0; num2[0] = 0; } for(int x = 0;x<len;x++){ if(stack.isEmpty()){ stack.push(array[x]); }else{ if(stack.peek() == array[x]) stack.pop(); else stack.push(array[x]); } } num1[0] = stack.pop(); num2[0] = stack.pop(); } }
用ArrayList,思路和前面的一致
时间复杂度为O(n2),空间复杂度为O(n)
链接:https://www.nowcoder.com/questionTerminal/e02fdb54d7524710a7d664d082bb7811 来源:牛客网 import java.util.ArrayList; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { ArrayList<Integer>list=new ArrayList<Integer>(); for(int i=0;i<array.length;i++) { if(!list.contains(array[i])) list.add(array[i]); else list.remove(new Integer(array[i])); } if(list.size()>1) { num1[0]=list.get(0); num2[0]=list.get(1); } } }
最好的方法:
时间复杂度为O(n),空间复杂度为O(1)
此题考察的是异或运算的特点:即两个相同的数异或结果为0。
此题用了两次异或运算特点:
(1)第一次使用异或运算,得到了两个只出现一次的数相异或的结果。
(2)因为两个只出现一次的数肯定不同,即他们的异或结果一定不为0,一定有一个位上有1。另外一个此位上没有1,我们可以根据此位上是否有1,将整个数组重新划分成两部分,一部分此位上一定有1,另一部分此位上一定没有1,然后分别对每部分求异或,因为划分后的两部分有这样的特点:其他数都出现两次,只有一个数只出现一次。因此,我们又可以运用异或运算,分别得到两部分只出现一次的数。
//num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 import java.util.*; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { int diff = 0; for(int num : array) diff ^= num; for(int num : array){ if((num & diff) == 0) num1[0] ^= num; else num2[0] ^= num; } } }
以上是关于算法的主要内容,如果未能解决你的问题,请参考以下文章