常见算法

排序&查找

二分查找

题目:在有序数组中查找一个值,返回该值的索引。(非递归方式&递归方式)

//非递归方式
public static int binaryFind(int[] list, int value) {
    int left = 0;
    int right = list.length - 1;
    int mid;
    while (left <= right) {// 当最小索引大于最大索引时,那么一定没有这个数了
        // mid = (left + right) / 2;//(不建议这样取中,因为可能数太大超出范围)
        // mid = left + ((right - left) >> 1);
        mid = left + (right - left) / 2;// 中间索引
        if (value == list[mid]) {//找到之后返回索引
            return mid;
        } else if (value > list[mid]) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return -1;// 没有找到,返回-1
}
//递归方式
public static int binaryFind2(int[] list, int value, int left, int right) {
    if (left <= right) {
        int mid = left + (right - left) / 2;
        if (list[mid] == value) {
            return mid;
        } else if (list[mid] > value) {
            return binaryFind2(list, value, left, mid - 1);
        } else {
            return binaryFind2(list, value, mid + 1, right);
        }
    } else
        return -1;
}

冒泡排序(优化后)

O(N^2) 时间

public static int[] bubbleSort(int[] a) {
    int leng = a.length;
    for (int i = 0; i < leng; i++) {
        boolean flag = true;
        for (int j = 0; j < leng - i - 1; j++) {
            if (a[j] > a[j + 1]) {
                int tem = a[j];
                a[j] = a[j + 1];
                a[j + 1] = tem;
                flag = false;
            }
        }
        if (flag) {
            break;
        }
        System.out.println("排序次数:" + i);
    }
    return a;
}

选择排序

O(N^2) 时间(每次选择最小的或最大的来生成一个数组)

public static int[] ChoiceSort(int[] a) {
    for (int i = 0; i < a.length; i++) {
        int min = i;
        for (int j = i + 1; j < a.length; j++) {
            if (a[min] > a[j]) {
                min = j;
            }
        }
        int tem = a[i];
        a[i] = a[min];
        a[min] = tem;
        //display(a);
    }
    return a;
}

快速排序

平均O(NLogN) 时间()

public static void sort(int[] list, int left, int right) {
    int division = division(list, left, right);
    if (left < right) {
        sort(list, left, division - 1);
        sort(list, division + 1, right);
    }
}

public static int division(int[] list, int left, int right) {
    int base = list[left];
    while (left < right) {
        while (left < right && list[right] >= base) {
            right--;
        }
        list[left] = list[right];
        while (left < right && list[left] <= base) {
            left++;
        }
        list[right] = list[left];
    }
    list[left] = base;
    return left;
}

反转字符串(多种方法)

方法1:利用栈实现

String str = "how are you";
Stack stack = new Stack();
char[] ch = str.toCharArray();
for (char c : ch) {
    stack.push(c);
}
while (!stack.isEmpty()) {
    System.out.print(stack.pop());
}

方法2.1:通过数组

public static String fanzhuan(String str) {
    if ("".equals(str)) {
        return "";
    }
    int len = str.length();
    char[] s = str.toCharArray();
    for (int i = 0; i < len ; i++) {
        s[i] = str.charAt(len - i - 1);
    }
    return new String(s);
}
//方法2.2:通过数组(减少一半)
public static String fanzhuan(String str) {
    if ("".equals(str)) {
        return "";
    }
    int len = str.length();
    char[] s = str.toCharArray();
    for (int i = 0; i < len / 2; i++) {
        s[i] = str.charAt(len - i - 1);
        s[len - 1 - i] = str.charAt(i);
    }
    return new String(s);
}
//方法3:使用StringBuilder逆序遍历
//方法4:使用递归
public static String reverse(String str) {
    if ("".equals(str))
        return "";
    int len = str.length();
    if (len == 1) {
        return str;
    }
    return reverse(str.substring(1)) + str.charAt(0);
}

Top k问题(多种方法)

堆排序之后取前k个:O(NlogN)

代码直接看堆排序即可

利用堆排序:O(NlogK)

伪代码:
heap[k] = make_heap(arr[1, k]);
for(i=k+1 to n){
         adjust_heap(heep[k],arr[i]);
}
return heap[k];
public static int[] top(int[] list, int k) {
    if (list.length <= k) {
        return list;
    }
    int[] array = new int[k];
    for (int i = 0; i < k; i++) {
        array[i] = list[i];
    }
    headSort(array);
    for (int i = k; i < list.length; i++) {
        if (array[0] < list[i]) {
            array[0] = list[i];
            headSort(array);
        }
    }
    return array;
}

public static int[] headSort(int[] inputList) {// 堆排序
    int length = inputList.length;
    for (int i = length / 2; i >= 0; i--) {// 建立初始堆
        heap(inputList, i, length);
    }
    for (int i = length - 1; i >= 0; i--) {// n-1次循环完成排列
        // 将最后一个元素和第一个元素进行交换(第一个元素是最大的,交换位置后,最大的就在排最后了)
        int tem = inputList[i];
        inputList[i] = inputList[0];
        inputList[0] = tem;
        heap(inputList, 0, i);// 将inputList中前i个记录重新调整为大顶堆
    }
    return inputList;
}

public static void heap(int[] list, int parent, int len) {// 构建堆
    int tem = list[parent];
    int child = 2 * parent + 1;
    while (child < len) {
        if (child + 1 < len && list[child + 1] > list[child]) {
            child++;
        }
        if (list[child] <= tem) {
            break;
        }
        list[parent] = list[child];
        parent = child;
        child = 2 * parent + 1;
    }
    list[parent] = tem;
}

使用优先队列PriorityQueue

(PriorityQueue就是通过堆实现的)

public static int[] topk(int[] list, int k) {
    if (list.length <= k) {
        return list;
    }
    PriorityQueue pq = new PriorityQueue<>(k, new Comparator() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 - o2;//最大堆
            //return  o2 - o1;//最小堆
        }
    });
    for (int num : list) {
        if (pq.size() < k) {
            pq.offer(num);
        } else if (pq.peek() < num) {
            pq.poll();
            pq.offer(num);
        }
    }
    int[] array = new int[k];
    for (int i = 0; i < k; i++) {
        array[i] = pq.poll();
    }
    return array;
}

动态规划

最长公共子串与最长公共子序列

最长公共子串与最长公共子序列(动归实现)

连续子数组的最大和

该算法在每次元素累加和小于0时,从下一个元素重新开始累加。实现代码如下:

public static int sum(int[] list) {
    int maxSum = 0;//记录最大的值
    int cursum = 0;//记录 暂时累加和
    for (int i = 0; i < list.length; i++) {
        cursum += list[i];
        if (cursum > maxSum) {//如果 暂时累加 大于历史最大值,则保存
            maxSum = cursum;
        }
        if (cursum < 0) {//如果 暂时累加和 小于0,则将暂时累加和更新为0
            cursum = 0;
        }
    }
    return maxSum;
}

链表

反转链表

    public static Node reverseListNode(Node head) {
        if (head == null || head.next == null) {// 单链表为空或只有一个节点,直接返回原单链表
            return head;
        }
        Node preNode = null;// 前一个节点指针
        Node curNode = head;// 当前节点指针
        Node nextNode = null;// 下一个节点指针
        while (curNode != null) {
            nextNode = curNode.next;// nextNode 指向下一个节点
            curNode.next = preNode;// 将当前节点next域指向前一个节点
            preNode = curNode;// preNode 指针向后移动
            curNode = nextNode;// curNode指针向后移动
        }
        return preNode;
    }

链表中倒数第k个结点

    public static Node findKthToTail(Node node, int k) {
        if (node == null || k == 0) {
            return null;
        }
        Node head = node;
        Node behind = node;
        for (int i = 0; i < k-1; i++) {
            if(head.next==null){
                return null;
            }
            head=head.next;
        }
        while(head.next!=null){
            head=head.next;
            behind=behind.next;
        }
        return behind;
    }

链表中环的入口结点

public static Node entryNodeOfLoop(Node node) {
        if (node == null || node.next == null) {
            return null;
        }
        Node fast = node;
        Node slow = node;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                fast = node;
                while (fast != slow) {
                    fast = fast.next;
                    slow = slow.next;
                }
                if(fast==slow){
                    return slow;
                }
            }
        }
        return null;
    }

二叉树

判断二叉树是否平衡

//class Tree {
//  int value;
//  Tree left;
//  Tree right;
//
//  public Tree(int value) {
//      this.value = value;
//      left = null;
//      right = null;
//  }
//}

public static boolean isBalance(Tree tree) {
    if (tree == null) {
        return true;
    }
    int left = treeDepth(tree.left);
    int right = treeDepth(tree.right);
    int diff = right - left;
    if (diff > 1 || diff < -1) {
        return false;
    }
    return isBalance(tree.left) && isBalance(tree.right);
}
public static int treeDepth(Tree tree) {//二叉树的深度
    if (tree == null) {
        return 0;
    }
    int left = treeDepth(tree.left);
    int right = treeDepth(tree.right);
    return left > right ? left + 1 : right + 1;
}

寻找二叉搜索树第k个结点

public static TreeNode findKthNode(TreeNode root, int k) {
TreeNode target=null;
if(root.left!=null){
target=findKthNode(root.left,k)
}
if(){
}
if(root.right!=null){
target=findKthNode(root.right,k)
}
}

贪心

买卖股票的最佳时机

找到局部最优解,然后再得到整体的最优解。我们可以从第一天的股票价钱出发,和第二天的对比,如果第二天比第一天价格更高了(稳赚),就赶紧买进第1天的,然后第二天卖出。同理,到了第二天,我就和第三天的价格做对比,只要后一天的价格高于今天的,我就买进今天的股票,到后一天再卖出。赚到的钱依次相加,得到最大的利润。当然如果后一天的价格比今天的低,我们就不买。

    public static int price(int[] list) {
        int result = 0;
        for (int i = 1; i < list.length; i++) {
            result = Math.max(result + list[i] - list[i - 1], result);
        }
        return result;
    }

你可能感兴趣的:(常见算法)