常见算法题

简介: 常见算法题

二分查找

 public static int binSearch(int[] a, int e) {
        int low = 0;
        int high = a.length - 1;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (a[mid] == e) {
                return mid;
            } else if (a[mid] < e) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return -1;
    }

快排

public static void main(String[] args) {
    int[] x = {3, 5, 1, 0, 2, 7, 6, 7, 9};
    quicSort(x, 0, x.length - 1);
    System.out.printf(Arrays.toString(x));
}
public static void quicSort(int[] a, int start, int end) {
    if (start >= end) {
        //如果只有一个元素,就不用再排下去了
        return;
    } else {
        //如果不止一个元素,继续划分两边递归排序下去
        int partition = divide(a, start, end);
        quicSort(a, start, partition - 1);
        quicSort(a, partition + 1, end);
    }
}
public static int divide(int[] a, int start, int end) {
    //每次都以最右边的元素作为基准值
    int base = a[end];
    //start一旦等于end,就说明左右两个指针合并到了同一位置,可以结束此轮循环。
    while (start < end) {
        while (start < end && a[start] <= base)
            //从左边开始遍历,如果比基准值小,就继续向右走
            start++;
        //上面的while循环结束时,就说明当前的a[start]的值比基准值大,应与基准值进行交换
        if (start < end) {
            //交换
            int temp = a[start];
            a[start] = a[end];
            a[end] = temp;
            //交换后,此时的那个被调换的值也同时调到了正确的位置(基准值右边),因此右边也要同时向前移动一位
            end--;
        }
        while (start < end && a[end] >= base)
            //从右边开始遍历,如果比基准值大,就继续向左走
            end--;
        //上面的while循环结束时,就说明当前的a[end]的值比基准值小,应与基准值进行交换
        if (start < end) {
            //交换
            int temp = a[start];
            a[start] = a[end];
            a[end] = temp;
            //交换后,此时的那个被调换的值也同时调到了正确的位置(基准值左边),因此左边也要同时向后移动一位
            start++;
        }
    }
    //这里返回start或者end皆可,此时的start和end都为基准值所在的位置
    return end;
}

单链表反转

class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }
}

两个链表合并

/*
public class ListNode {
    int val;
    ListNode next = null;
    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        ListNode head = new ListNode(0);
        ListNode tmp = head;
        while(list1!=null&&list2!=null){
            if(list1.val<list2.val){//谁小先挂谁
                tmp.next = list1;
                list1 = list1.next;
            }else{
                tmp.next = list2;
                list2 = list2.next;
            }
            tmp = tmp.next;
        }//代码走到这,一个为空一个不为空
        if(list1!=null){
            tmp.next = list1;
        }
        if(list2!=null){
            tmp.next = list2;
        }
        return head.next;
    }
}

链表环的入口

public class Solution {
    //判断有没有环,返回相遇的地方
    public ListNode hasCycle(ListNode head) {
        //先判断链表为空的情况
        if(head == null) 
            return null;
        //快慢双指针
        ListNode fast = head; 
        ListNode slow = head;
        //如果没环快指针会先到链表尾
        while(fast != null && fast.next != null){ 
            //快指针移动两步
            fast = fast.next.next; 
            //慢指针移动一步
            slow = slow.next; 
            //相遇则有环,返回相遇的位置
            if(fast == slow) 
                return slow;
        }
        //到末尾说明没有环,返回null
        return null; 
    }
    public ListNode EntryNodeOfLoop(ListNode pHead) {
        ListNode slow = hasCycle(pHead);
        //没有环
        if(slow == null) 
            return null;
        //快指针回到表头
        ListNode fast = pHead; 
        //再次相遇即是环入口
        while(fast != slow){ 
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

有效的括号

import java.util.*;
public class Solution {
    /**
     * 
     * @param s string字符串 
     * @return bool布尔型
     */
    public boolean isValid (String s) {
        // write code here
        Stack<Character> stack = new Stack<>();
        Map<Character,Character> map = new HashMap<>();
        map.put('(',')');
        map.put('[',']');
        map.put('{','}');
        for(Character c : s.toCharArray()) {
            if (!stack.isEmpty() && c == map.get(stack.peek())){
                stack.pop();
            } else {
                stack.add(c);
            }
        }
        return stack.isEmpty();
    }
}

滑动窗口最大值

import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size) {
        if (num == null || size == 0 || size > num.length) {
            return new ArrayList<>();
        }
        LinkedList<Integer> qmax = new LinkedList<>();
        ArrayList<Integer> result = new ArrayList<>();
        for(int i = 0;i<num.length;i++) {
            //保证在窗口范围内队头元素存放的是最大值,第二个元素次大
            while(!qmax.isEmpty() && num[qmax.peekLast()] <= num[i]){
                qmax.pollLast();
            }
            qmax.addLast(i);
            //如果队头值已经过期了,则移除
            if (i - size == qmax.peekFirst()) {
                qmax.pollFirst();
            }
            if (i-size+1 >= 0) {
                result.add(num[qmax.peekFirst()]);
            }
        }
        return result;
    }
}

二叉树公共祖先

public int lowestCommonAncestor(TreeNode root, int o1, int o2) {
        return helper(root, o1, o2).val;
    }
    public TreeNode helper(TreeNode root, int o1, int o2) {
        if (root == null || root.val == o1 || root.val == o2)
            return root;
        TreeNode left = helper(root.left, o1, o2);
        TreeNode right = helper(root.right, o1, o2);
        //如果left为空,说明这两个节点在root结点的右子树上,我们只需要返回右子树查找的结果即可
        if (left == null)
            return right;
        //同上
        if (right == null)
            return left;
        //如果left和right都不为空,说明这两个节点一个在root的左子树上一个在root的右子树上,
        //我们只需要返回cur结点即可。
        return root;
    }

之字打印二叉树

public class questionthree {
  public static void main(String[] args) {
    TreeNode root = new TreeNode(8);
    root.left = new TreeNode(6);
    root.right = new TreeNode(10);
    root.left.left = new TreeNode(5);
    root.left.right = new TreeNode(7);
    root.right.left = new TreeNode(9);
    root.right.right = new TreeNode(11);
    List<List<Integer>> res = new ArrayList<>();
    res = levelOrder(root);
    for(int i = 0; i<res.size();i++){
      System.out.println(res.get(i));
    }
  }
  public static List<List<Integer>> levelOrder(TreeNode root){
    List<List<Integer>> ans = new ArrayList<>();
    if(root == null) return ans;
    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root);//把根节点放进队列,开始程序
    boolean flag = true;  //控制列表是顺序还是逆序的标志
    while(!queue.isEmpty()){ //如果队列不是空的,说明二叉树不会遍历完,如果有下一层,会在当前这层往队列里加入下一层的节点
      int size = queue.size(); //首先得到当前要这一层要处理的节点数
      List<Integer> curlevel = new ArrayList<>(); //初始化用来放当前这层节点的值的容器
      while(--size >= 0){  //按照要处理节点的个数来处理
        TreeNode cur = queue.remove();  //每处理一个节点,就把一个节点移出队列
        curlevel.add(cur.val);  //同时把要处理节点的值放进当前层的容器中
        if(cur.left != null) queue.add(cur.left);  //如果当前节点有左右子节点,就加入到队列中
        if(cur.right != null) queue.add(cur.right);
      }
      if(flag == false) {  //如果标志位false,将列表逆序
        Collections.reverse(curlevel);
      }
      ans.add(curlevel);
      flag = !flag;  //下一层,flag取反
    }
    return ans;
  }
}

买卖股票最佳时机

dp[i]=max(dp[i-1],prices[i]-min(prices[0:i]))

class Solution {
    public int maxProfit(int[] prices) {
        int maxProfit = 0, minPrice = prices[0];
        for (int i = 1; i < prices.length; i++) {
            maxProfit = Math.max(maxProfit, prices[i] - minPrice);
            minPrice = Math.min(minPrice, prices[i]);
        }
        return maxProfit;
    }
}
class Solution {
    public int maxProfit(int[] prices) {
        int[] dp = new int[prices.length];
        int minPrice = prices[0];
        // base case: dp_0 = 0
        dp[0] = 0;
        // state transition: dp[i]=max(dp[i-1],prices[i]-minPrice)
        for (int i = 1; i < prices.length; i++) {
            dp[i] = Math.max(dp[i - 1], prices[i] - minPrice);
            minPrice = Math.min(minPrice, prices[i]);
        }
        return dp[prices.length - 1];
    }
}

力扣


打家劫舍

dp[i] = max( dp[i-2] + nums[i] , dp [i-1])

dp[i]=max(dp[i−2]+nums[i],dp[i−1])
class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int length = nums.length;
        if (length == 1) {
            return nums[0];
        }
        int[] dp = new int[length];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        for (int i = 2; i < length; i++) {
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[length - 1];
    }
}

回文子串

这里需要二维的 dp[][] 数组,dp[i][j] 表示子串 [i..j] 是否为回文子串

当我们判断 [i..j] 是否为回文子串时,只需要判断 s[i] == s[j],同时判断 [i-1..j-1] 是否为回文子串即可

需要注意有两种特殊情况:[i, i] or [i, i + 1],即:子串长度为 1 或者 2。所以加了一个条件限定 j - i < 2

状态转移方程如下:

dp[i][j] = (s[i] == s[j]) && (j - i < 2 || dp[i + 1][j - 1])

public int countSubstrings(String s) {
    int ans = 0;
    int n = s.length();
    boolean[][] dp = new boolean[n][n];
    for (int j = 0; j < n; j++) {
        for (int i = 0; i <= j; i++) {
            if (s.charAt(j) == s.charAt(i) && (j - i < 2 || dp[i + 1][j - 1])) {
                dp[i][j] = true;
                ans++;
            }
        }
    }
    return ans;
}

接雨水

public int trap(int[] height) {
    int sum = 0;
    Stack<Integer> stack = new Stack<>();
    int current = 0;
    while (current < height.length) {
        //如果栈不空并且当前指向的高度大于栈顶高度就一直循环
        while (!stack.empty() && height[current] > height[stack.peek()]) {
            int h = height[stack.peek()]; //取出要出栈的元素
            stack.pop(); //出栈
            if (stack.empty()) { // 栈空就出去
                break; 
            }
            int distance = current - stack.peek() - 1; //两堵墙之前的距离。
            int min = Math.min(height[stack.peek()], height[current]);
            sum = sum + distance * (min - h);
        }
        stack.push(current); //当前指向的墙入栈
        current++; //指针后移
    }
    return sum;
}

岛屿问题

class Solution {
    public int numIslands(char[][] grid) {
        int count = 0;
        for(int i = 0; i < grid.length; i++) {
            for(int j = 0; j < grid[0].length; j++) {
                if(grid[i][j] == '1'){
                    dfs(grid, i, j);
                    count++;
                }
            }
        }
        return count;
    }
    private void dfs(char[][] grid, int i, int j){
        if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return;
        grid[i][j] = '0';
        dfs(grid, i + 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i - 1, j);
        dfs(grid, i, j - 1);
    }
}


相关文章
|
3月前
|
算法
算法题(5)
算法题(5)
28 11
|
3月前
|
算法
算法题(2)
算法题(2)
32 3
|
4月前
|
人工智能 算法 搜索推荐
什么是算法?一切皆算法
如果有人问我什么算法?我就一句话:算法就是对一类问题的最优求解路径。
|
5月前
|
算法 调度 C#
|
7月前
|
算法 C++ 容器
【C++11新算法】all_of、any_of、none_of算法
【C++11新算法】all_of、any_of、none_of算法
158 0
|
算法
秒懂算法 | 基环树
图论是一个“巨大”的专题,有大量的知识点,有众多广为人知的问题,有复杂的应用场景。 图论算法常常建立在复杂的数据结构之上。
346 0
秒懂算法 | 基环树
|
JavaScript 算法 前端开发
vueDiff 算法解读
前言 在面试中谈到 vue 源码,一般都会扯扯 diff 算法,而这个 diff 又在网上传的神乎其神的,说是提升了页面更新性能,我们一起看看到底咋回事吧
|
机器学习/深度学习 算法 TensorFlow
秒懂算法 | RIB算法
结合微观行为序列的推荐(recommendation with sequences of micro behaviors, RIB)在物品序列的基础上,加入了对异构行为和停留时间的建模。对异构行为的建模使得模型能够捕捉更加细粒度的用户兴趣,而用户在某个页面上的停留时间则反映了用户对这个页面的感兴趣程度,并且停留时间越长,购买商品的转化率通常也会越高。
276 0
秒懂算法 | RIB算法
|
算法 索引
紫书之子集生成三种算法
紫书之子集生成三种算法
紫书之子集生成三种算法

热门文章

最新文章