算法

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;
    }
}
View Code

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;
 
    }
}
View Code

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;
    }
View Code

 

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;
    }
}
View Code

 二分法:

技术分享图片
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;
    }
}
View Code

 

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);
    }
}
View Code

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;
    }
}
View Code

 

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);
    }
}
View Code

 

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();
}
}
View Code

 用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);
                    }
        }
}
View Code

 最好的方法:

时间复杂度为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;
        }
    }
}
View Code

 

 

 


以上是关于算法的主要内容,如果未能解决你的问题,请参考以下文章

片段(Java) | 机试题+算法思路+考点+代码解析 2023

如何标记从卷积神经网络的分割算法生成的图像片段?

从搜索文档中查找最小片段的算法?

C语言100个经典算法源码片段

一致性哈希算法PHP测试片段

视频二次裁剪时间计算出原片的时间片段算法