面試常見高頻算法題總結


一、鏈表相關

1.鏈表反轉

class Solution {
    public ListNode reverseList(ListNode head) {
        // base case
        if(head == null || head.next == null) return head;  
        
        ListNode first = head;
        ListNode result = null;//建立一個新的節點用來存放結果
        ListNode second = null;
        while(first != null){ //遍歷輸入鏈表,開始處理每一個節點
            second = first.next;  //先處理第一個節點first,所以需要一個指針來存儲first的后繼
            first.next = result; //將first放到新鏈表頭節點的頭部
            result = first; //移動新鏈表的頭指針,讓它始終指向新鏈表頭部
            first = second; //繼續處理原鏈表的節點,即之前指針存放的后繼,循環往復
        }
        return result;
    }
}

 2.k個一組翻轉鏈表(力扣 25) --------比較難

 

3.判斷鏈表是否有環

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
   public boolean hasCycle(ListNode head) {//設置快慢指針,若有環一定會在環里面相遇。否則會有null值
    if(head==null) return false;
    ListNode walker = head;
    ListNode runner = head;
    while(runner.next!=null && runner.next.next!=null) {
        walker = walker.next;
        runner = runner.next.next;
        if(walker==runner) return true;
    }
    return false;
  }
}

//也可以采用hashmap把每一個節點存儲起來,如果地址相同則存在節點

 

二、數組、字符串巧妙解法相關

1.不使用除法實現除自身外數組元素的乘積(力扣 238)

public class Solution {
    
   public int[] productExceptSelf(int[] nums) {
       int n = nums.length;
       int[] res = new int[n];
       res[0] = 1;
       for (int i = 1; i < n; i++) {
          res[i] = res[i - 1] * nums[i - 1];
       }
       int right = 1;
       for (int i = n - 1; i >= 0; i--) {
          res[i] *= right;
          right *= nums[i];
      }
       return res;
    }
}

 

 

二、樹相關

1.給定一顆二叉搜索樹,返回該二叉搜索樹第K大的節點

//思路:二叉搜索樹按照中序遍歷的順序打印出來正好就是排序好的順序。
//     所以,按照中序遍歷順序找到第k個結點就是結果。
public class Solution {
   int index = 0; //計數器
    TreeNode KthNode(TreeNode root, int k)
    {
        if(root != null){ //中序遍歷尋找第k個
            TreeNode node = KthNode(root.left,k);
            if(node != null)
                return node;
            index ++;
            if(index == k)
                return root;
            node = KthNode(root.right,k);
            if(node != null)
                return node;
        }
        return null;
    }
}

 2.二叉樹最小深度

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
//為什么采用分治的思想而不是求數最大深度思想,因為可能為單鏈表(鏈表是特殊樹)沒法處理
class Solution {
     public int minDepth(TreeNode root) {
        if(root == null) return 0;
        int left = minDepth(root.left);
        int right = minDepth(root.right);
        return (left == 0 || right == 0) ? left + right + 1//為什么可以寫成left + right + 1
            : Math.min(left,right) + 1;         //因為left 跟right 必有一個為0,所以..
       
    }
}

 

3.二叉樹最大深度

 

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
   public int maxDepth(TreeNode root) {
        if(root == null) {
            return 0;
        } else{
            return 1+ Math.max(maxDepth(root.left), maxDepth(root.right));
        }
    }
}

 

 

三、動態規划相關

1.兩個字符串的最長公共子序列長度

 

 

 

class Solution {
//dp[i][j]表示 0-(i-1) 0-(j-1)之間最長子序列
public int longestCommonSubsequence(String s1, String s2) { int[][] dp = new int[s1.length() + 1][s2.length() + 1]; for (int i = 0; i < s1.length(); ++i) for (int j = 0; j < s2.length(); ++j) if (s1.charAt(i) == s2.charAt(j)) dp[i + 1][j + 1] = 1 + dp[i][j]; else dp[i + 1][j + 1] = Math.max(dp[i][j + 1], dp[i + 1][j]); return dp[s1.length()][s2.length()]; } }

 

 

2.求連續子數組的最大和

class Solution {
   public static int maxSubArray(int[] A) {
    int maxSoFar=A[0], maxEndingHere=A[0];
    for(int i=1;i<A.length;++i){
        maxEndingHere = Math.max(A[i], maxEndingHere+A[i]);
        maxSoFar = Math.max(maxEndingHere, maxSoFar);
    }
    return maxSoFar;
  }
}

 

四、排序

1.快排

public static void quickSort(int[] list, int left, int right) {
        if (left < right) {
            // 分割數組,找到分割點
            int point = partition(list, left, right);

            // 遞歸調用,對左子數組進行快速排序
            quickSort(list, left, point - 1);
            // 遞歸調用,對右子數組進行快速排序
            quickSort(list, point + 1, right);
        }
    }

    /**
     * 分割數組,找到分割點
     */
    public static int partition(int[] list, int left, int right) {
        // 用數組的第一個元素作為基准數
        int first = list[left];
        while (left < right) {
            while (left < right && list[right] >= first) {
                right--;
            }
            // 交換
            swap(list, left, right);

            while (left < right && list[left] <= first) {
                left++;
            }
            // 交換
            swap(list, left, right);
        }
        // 返回分割點所在的位置
        return left;
    }

    /**
     * 交換數組中兩個位置的元素
     */
    public static void swap(int[] list, int left, int right) {
        int temp;
        if (list != null && list.length > 0) {
            temp = list[left];
            list[left] = list[right];
            list[right] = temp;
        }
    }

 

 2.二路歸並排序

public class MergeSort {
    /**
     * 歸並排序(Merge Sort)與快速排序思想類似:將待排序數據分成兩部分,繼續將兩個子部分進行遞歸的歸並排序;然后將已經有序的兩個子部分進行合並,最終完成排序。
     * 其時間復雜度與快速排序均為O(nlogn),但是歸並排序除了遞歸調用間接使用了輔助空間棧,還需要額外的O(n)空間進行臨時存儲。從此角度歸並排序略遜於快速排序,但是歸並排序是一種穩定的排序算法,快速排序則不然。
     * 所謂穩定排序,表示對於具有相同值的多個元素,其間的先后順序保持不變。對於基本數據類型而言,一個排序算法是否穩定,影響很小,但是對於結構體數組,穩定排序就十分重要。例如對於student結構體按照關鍵字score進行非降序排序:
     */
    public static void main(String[] args) {
        int[] list = {50, 10, 90, 30, 70};
        System.out.println("************歸並排序************");
        System.out.println("排序前:");
        display(list);
        System.out.println("排序后:");
        mergeSort(list, new int[list.length], 0, list.length - 1);
        display(list);
    }

    /**
     * 歸並排序算法
     * @param list     待排序的列表
     * @param tempList 臨時列表
     * @param head     列表開始位置
     * @param rear     列表結束位置
     */
    public static void mergeSort(int[] list, int[] tempList, int head, int rear) {
        if (head < rear) {
            // 取分割位置
            int middle = (head + rear) / 2;
            // 遞歸划分列表的左序列
            mergeSort(list, tempList, head, middle);
            // 遞歸划分列表的右序列
            mergeSort(list, tempList, middle + 1, rear);
            // 列表的合並操作
            merge(list, tempList, head, middle + 1, rear);
        }
    }

    /**
     * 合並操作(列表的兩兩合並)
     * @param list
     * @param tempList
     * @param head
     * @param middle
     * @param rear
     */
    public static void merge(int[] list, int[] tempList, int head, int middle, int rear) {
        // 左指針尾
        int headEnd = middle - 1;
        // 右指針頭
        int rearStart = middle;
        // 臨時列表的下標
        int tempIndex = head;
        // 列表合並后的長度
        int tempLength = rear - head + 1;

        // 先循環兩個區間段都沒有結束的情況
        while ((headEnd >= head) && (rearStart <= rear)) {
            // 如果發現右序列大,則將此數放入臨時列表
            if (list[head] < list[rearStart]) {
                tempList[tempIndex++] = list[head++];
            } else {
                tempList[tempIndex++] = list[rearStart++];
            }
        }

        // 判斷左序列是否結束
        while (head <= headEnd) {
            tempList[tempIndex++] = list[head++];
        }

        // 判斷右序列是否結束
        while (rearStart <= rear) {
            tempList[tempIndex++] = list[rearStart++];
        }

        // 交換數據
        for (int i = 0; i < tempLength; i++) {
            list[rear] = tempList[rear];
            rear--;
        }
    }

    /**
     * 遍歷打印
     */
    public static void display(int[] list) {
        if (list != null && list.length > 0) {
            for (int num :list) {
                System.out.print(num + " ");
            }
            System.out.println("");
        }
    }
}

 

 

 

五、LRU LFU

1.lru采用雙鏈表+hashmap實現

class LRUCache {
    int size;
    Node head,tail;
    HashMap<Integer,Node> hm;
    public LRUCache(int capacity) { 
         size=capacity;
         head=tail=null;
         hm=new HashMap<>();
    }
    
    public int get(int key) {
        
         if(!hm.containsKey(key))
         {
             return -1;
         }
         else
         {
             Node ref=hm.get(key);
             if(ref==head) return ref.val;
             if(ref!=head && ref!=tail)
             {
                 ref.Llink.Rlink=ref.Rlink;
                 ref.Rlink.Llink=ref.Llink;
                 
             }
             else if(ref!=head && ref==tail)
             {
                 tail=tail.Llink;
                 tail.Rlink=null;
                 
             }
             ref.Llink=null;
             ref.Rlink=head;
             head.Llink=ref;
             head=ref;
             return ref.val;
         }
        
        
      
    }
    
    public void put(int key, int value) {
      
         if(hm.containsKey(key))
         {
             hm.get(key).val=value;
             this.get(key);
         }
         else
         {
             Node temp=new Node(value,key);
            
             if(hm.size()<size)
             {   hm.put(key,temp);
                 if(head==null)
                 {
                     head=temp;
                     tail=temp;
                 }
                 else
                 {
                     temp.Rlink=head;
                     head.Llink=temp;
                     head=temp;
                 }
             }
             else
             {
                 if(tail==head)
                 {
                     hm.remove(tail.key);
                     hm.put(key,temp);
                     head=tail=temp;
                 }
                 else
                 {
                     hm.remove(tail.key);
                     hm.put(key,temp);
                     Node help=tail;
                     tail=tail.Llink;
                     tail.Rlink=null;
                     help.Llink=null;
                     temp.Rlink=head;
                     head.Llink=temp;
                     head=temp;
                 }
                  
                    
             }
             
         }
        
        
    }    
}

class Node{
    int val;
    int key;
    Node Rlink;
    Node Llink;
    Node(int val,int key)
    {   this.key=key;
        this.val=val;
        Rlink=null;
        Llink=null;
    }
   
}

 

2.lfu

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM