手把手带你刷剑指offer

剑指offer题解

  • LRU缓存
  • 颜色分类
  • 最小的k个数
  • 数组中第K大的数字
  • 合并k个已排序的链表
  • 前K个高频单词
  • 前k个高频元素
  • 字符串中第二大的数字
  • 字符串的最大公因子
  • Excel表列名称(1->A)
  • Excel表序列化(A->1)
  • 字符串转整数
  • 用两个栈实现队列
  • 包含min函数的栈
  • 数组中重复的数字
  • 二维数组中额的查找
  • 0~n-1中缺失的数字
  • 二维数组中查找
  • 替换空格
  • 从头到尾打印链表
  • 重建二叉树(根据前序遍历和中序遍历来构建二叉树)
  • 用两个栈实现队列
  • 旋转数组的最小数字
  • 菲波那切数列
  • 菲波那切数列(取模)
  • 爬楼梯
  • 跳台阶
  • 跳台阶扩展问题
  • 矩阵覆盖
  • 二进制中一的个数
  • 数值的整数次方
  • 调整数组顺序使奇数位于偶数前面
  • 链表中倒数第k个结点
  • 反转链表
  • 合并两个有序链表
  • 树的子结构
  • 二叉树的镜像
  • 从上往下打印二叉树
  • 复杂链表的复刻
  • 二叉搜索树和双向链表
  • 两个链表的第一个公共节点
  • 链表中环的入口节点
  • 删除链表中重复的节点
  • 两数相加
  • 二叉树的镜像
  • 对称二叉树
  • 按之字形顺序打印二叉树
  • 数组中的逆序对
  • 和为s的两个数字
  • 滑动窗口最大值
  • 把数组排成最小的数
  • 表达式求值

根据牛客的顺序来刷的,附上链接: https://www.nowcoder.com/ta/coding-interviews

  • 获取map中key和value的集合
 public static void main(String[] args) {
        HashMap<String,Integer> map=new HashMap<>() ;
        map.put("aaaa",111);
        map.put("bbbb",222);
        map.put("cccc",333);
        map.put("dddd",444);
        Set<String> set = map.keySet();
        ArrayList<String> list1 = new ArrayList<>(set);
        System.out.println(list1);
        Collection<Integer> collections = map.values();
        ArrayList<Integer> list2 = new ArrayList<>(collections);
        System.out.println(list2);
    }

LRU缓存

https://leetcode-cn.com/problems/lru-cache-lcci/

class LRUCache {

    class Node{
        int key;
        int value;
        Node prev;
        Node next;
        Node(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }
    int capacity = 0;
    int len = 0;
    HashMap<Integer, Node> map = new HashMap<>();
    Node head = new Node(-1, -1);
    Node tail = new Node(-1, -1);
    public LRUCache(int capacity) {
        this.capacity = capacity;
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        //如果Node在map中存在
        Node node = map.get(key);
        if(node != null) {
            //把这个节点从当前位置移除,并移动到头部
            removeNode(node);
            moveToHead(node);
            return node.value;
        }else {
            return -1;
        }
    }
    
    public void put(int key, int value) {
        Node node = map.get(key);
        //如果node结点在map中存在
        if(node != null){
            //更新结点的值
            node.value = value;
            //从当前位置移除,并移到首部
            removeNode(node);
            moveToHead(node);
        }else{
            //元素不存在,先判断容量是否满了
            if(len == capacity){
                //容量满了移除最近最久未使用的,也就是尾结点的前面一个结点,同时删除map中的key,长度减一
                map.remove(tail.prev.key);
                removeNode(tail.prev);
                len--;
            }
            //插入新结点,把新结点移到首部,存入map中
            Node newNode = new Node(key, value);
            moveToHead(newNode);
            map.put(key, newNode);
            len++;
        }
    }
    public void removeNode(Node node){
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    public void moveToHead(Node node){
        node.prev = head;
        node.next =  head.next;
        head.next = node;
        node.next.prev = node;
    }
}

颜色分类

//快排
 public void quickSort(int[] arr, int l, int r) {
        if(l > r) {
            return ;
        }
        int i = l, j = r;
        int tmp = arr[i];
        while(i < j) {
            while(i < j && arr[j] >= tmp) {
                j--;
            }
            arr[i] = arr[j];
            while(i < j && arr[i] <= tmp) {
                i++;
            }
            arr[j] = arr[i];
        }
        arr[i] = tmp;
        quickSort(arr, l, i - 1);
        quickSort(arr, i + 1, r);
    }
//归并
    public void mergeSort(int[] arr, int l, int r) {
        if(l >= r) {
            return ;
        }
        int mid = l + r >> 1;
        mergeSort(arr, l, mid);
        mergeSort(arr, mid + 1, r);
        int i = l, j = mid + 1;
        int[] tmp = new int[r - l + 1];
        int k = 0;
        while(i <= mid && j <= r) {
            if(arr[i] <= arr[j]) {
                tmp[k++] = arr[i++];
            }else {
                tmp[k++] = arr[j++];
            }
        }
        while(i <= mid) {
            tmp[k++] = arr[i++];
        }
        while(j <= r) {
            tmp[k++] = arr[j++];
        }
        for(i = l,j = 0; i <= r; i++, j++) {
            arr[i] = tmp[j];
        }
    }


//快排优化

```java
public class test {
    public static void insertSort(int[] array,int low,int high)
    {
        int tmp,j;
        for(int i=low;i<=high;i++)
        {
            tmp=array[i];
            j=i-1;
            for(;j>=low;j--)
            {
                if(array[j]>tmp)
                {
                    array[j+1]=array[j];
                }else{
                    break;
                }
            }
            array[j+1]=tmp;
        }
    }

    public static void medianOfThree(int[] arr, int l, int r) {
        int mid = (l + r) / 2;
        //array[mid] <= array[low] <= array[high]
        if(arr[l] < arr[mid]) {
            swap(arr, l, mid);
        }//array[mid] <= array[low]
        if(arr[l] > arr[r]) {
            swap(arr, l, r);
        }//array[low] <= array[high]
        if(arr[mid] > arr[r]) {
            swap(arr, mid, r);
        }//array[mid] <= array[high]
    }

    private static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public static void quickSort(int[] arr, int l, int r) {
        if(l > r) {
            return ;
        }
        if(r - l + 1 <= 50) {
            //使用插入排序
            insertSort(arr, l, r);
            return;//记着这里一定要return  这里说明 这个区别范围有序了 直接结束
        }

        int i = l, j = r;
        medianOfThree(arr, l, r);
        int tmp = arr[i];
        while(i < j) {
            while(i < j && arr[j] >= tmp) {
                j--;
            }
            arr[i] = arr[j];
            while(i < j && arr[i] <= tmp) {
                i++;
            }
            arr[j] = arr[i];
        }
        arr[i] = tmp;
        quickSort(arr, l, i - 1);
        quickSort(arr, i + 1, r);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int[] arr = new int[]{2, 3, 1, 2, 6, 7, 9};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }
}

//堆排

    public void adjustDown(int[] arr, int parent, int len) {
        int child = 2 * parent + 1;
        while(child < len) {
            if(child + 1 < len && arr[child] < arr[child + 1]) {
                child++;
            }
            if(arr[child] > arr[parent]) {
                int tmp = arr[parent];
                arr[parent] = arr[child];
                arr[child] = tmp;
                parent = child;
                child = 2 * parent + 1;
            }else {
                break;
            }
        }
    }
    public void createBigHeap(int[] arr) {
        for(int i = ((arr.length - 1 - 1) / 2); i >= 0; i--) {
            adjustDown(arr, i, arr.length);
        }
    }
    public void heapSprt(int[] arr) {
        createBigHeap(arr);
        int end = arr.length - 1;
        while(end > 0) {
            int tmp = arr[0];
            arr[0] = arr[end];
            arr[end] = tmp;
            adjustDown(arr, 0, end);
            end--;
        }
    }

最小的k个数

https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(arr == null || arr.length == 0 || k == 0) {
            return new int[0];
        }
        PriorityQueue<Integer> bigHeap = new PriorityQueue<>((o1, o2)->(o2 - o1));
        for(int num : arr) {
            if(bigHeap.size() < k) {
                bigHeap.offer(num);
            }else if(bigHeap.peek() > num) {
                bigHeap.poll();
                bigHeap.offer(num);
            }
        }
        int[] ret = new int[k];
        int index = 0;
        while(!bigHeap.isEmpty()) {
            ret[index++] = bigHeap.poll();
        }
        return ret;
    }
}

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
            if (k >= arr.length) return arr;
        return quickSort(arr, k, 0, arr.length - 1);
    }
    private int[] quickSort(int[] arr, int k, int l, int r) {
        int i = l, j = r;
        while (i < j) {
            while (i < j && arr[j] >= arr[l]) j--;
            while (i < j && arr[i] <= arr[l]) i++;
            swap(arr, i, j);
        }
        swap(arr, i, l);
        if (i > k) return quickSort(arr, k, l, i - 1);
        if (i < k) return quickSort(arr, k, i + 1, r);
        return Arrays.copyOf(arr, k);
    }
    private void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

数组中第K大的数字

https://leetcode-cn.com/problems/xx4gT2/

class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> bigHeap = new PriorityQueue<>();
        for(int num : nums) {
            if(bigHeap.size() < k) {
                bigHeap.offer(num);
            }else if(bigHeap.peek() < num) {
                bigHeap.poll();
                bigHeap.offer(num);
            }
        }
        return bigHeap.peek();
    }
}

合并k个已排序的链表

import java.util.*;
public class Solution {
    public ListNode mergeKLists(ArrayList<ListNode> lists) {
        if (lists == null) {
            return null;
        }
        PriorityQueue<ListNode> queue = new PriorityQueue<>((ListNode a, ListNode b) -> (a.val - b.val));
        for (ListNode list : lists) {
            if (list != null) {
                queue.add(list);
            }
        }
        ListNode newHead = new ListNode(-1);
        ListNode tmp = newHead;

        while (!queue.isEmpty()) {
            ListNode node = queue.poll();
            tmp.next = node;
            if (node.next != null) {
                queue.add(node.next);
            }
            tmp = tmp.next;
        }
        return newHead.next;
    }
}

前K个高频单词

https://leetcode-cn.com/problems/top-k-frequent-words/

public class Solution {

     public List<String> topKFrequent(String[] words, int k) {
        // 1.先用哈希表统计单词出现的频率
        Map<String, Integer> count = new HashMap();
        for (String word : words) {
            count.put(word, count.getOrDefault(word, 0) + 1);
        }
        // 2.构建小根堆 这里需要自己构建比较规则 此处为 lambda 写法 Java 的优先队列默认实现就是小根堆
        PriorityQueue<String> minHeap = new PriorityQueue<>((s1, s2) -> {
            if (count.get(s1).equals(count.get(s2))) {
                return s2.compareTo(s1);
            } else {
                return count.get(s1) - count.get(s2);
            }
        });
        // 3.依次向堆加入元素。
        for (String s : count.keySet()) {
            minHeap.offer(s);
            // 当堆中元素个数大于 k 个的时候,需要弹出堆顶最小的元素。
            if (minHeap.size() > k) {
                minHeap.poll();
            }
        }
        // 4.依次弹出堆中的 K 个元素,放入结果集合中。
        List<String> res = new ArrayList<String>(k);
        while (minHeap.size() > 0) {
            res.add(minHeap.poll());
        }
        // 5.注意最后需要反转元素的顺序。
        Collections.reverse(res);
        return res;
    }        
}

前k个高频元素

https://leetcode-cn.com/problems/top-k-frequent-elements/

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        // 统计每个数字出现的次数
        Map<Integer, Integer> counter = IntStream.of(nums).boxed().collect(Collectors.toMap(e -> e, e -> 1, Integer::sum));
        // 定义小根堆,根据数字频率自小到大排序
        Queue<Integer> pq = new PriorityQueue<>((v1, v2) -> counter.get(v1) - counter.get(v2));
        // 遍历数组,维护一个大小为 k 的小根堆:
        // 不足 k 个直接将当前数字加入到堆中;否则判断堆中的最小次数是否小于当前数字的出现次数,若是,则删掉堆中出现次数最少的一个数字,将当前数字加入堆中。
        counter.forEach((num, cnt) -> {
            if (pq.size() < k) {
                pq.offer(num);
            } else if (counter.get(pq.peek()) < cnt) {
                pq.poll();
                pq.offer(num);
            }
        });
        // 构造返回结果
        int[] res = new int[k];
        int idx = 0;
        for (int num: pq) {
            res[idx++] = num;
        }
        return res;
    }
}

字符串中第二大的数字

https://leetcode-cn.com/problems/second-largest-digit-in-a-string/

class Solution {
    public int secondHighest(String s) {
        // 顾名思义,first 是用来记录第一个的,second 是用来记录第二个的
        int first = -1, second = -1;
        for (char c : s.toCharArray()) {
            // 如果 c 是一个数字,那么就进行检查处理
            if (Character.isDigit(c)) {
                // 首先字符转换成数字
                int num = c - '0';
                // 如果 first 还没有赋值呢,那么就直接赋值
                if (first == -1) first = num;
                // first 已经带值,而且 num 比 first 还大,那么就更新它们
                else if (num > first) {
                    second = first;
                    first = num;
                } else if (num < first && num > second)
                    // 如果介于两者中间,那么就只更新第二个值
                    second = num;
            }
        }
        return second;
    }
}

字符串的最大公因子

https://leetcode-cn.com/problems/greatest-common-divisor-of-strings/

class Solution {
    public String gcdOfStrings(String str1, String str2) {
         int len1 = str1.length(), len2 = str2.length();
        boolean flag = (len1 > len2) ? isPresence(str1, str2):isPresence(str2, str1);
        if (!flag)  return "";
        
        // 求len1 和 len2 的最小公约数
        int count = gcd(len1, len2);
        String ret = str1.substring(0, count);
        return ret;
    }
    
    private boolean isPresence(String str1, String str2) {
        int len = str2.length();
        // 包含的元素一致,且顺序对得上
        for (int i = 0; i < str1.length(); i++) {
            if (str1.charAt(i) != str2.charAt(i%len))   return false;
        }
        
        return true;
    }
    
    private int gcd(int a, int b) {
        if (a % b == 0) return b;
        else   return gcd(b, a%b);
    }
}

Excel表列名称(1->A)

https://leetcode-cn.com/problems/excel-sheet-column-title/

class Solution {
    public String convertToTitle(int n) {
        if (n <= 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        while (n > 0) {
            n--;
            sb.append((char) (n % 26 + 'A'));
            n =n / 26;
        }
        return sb.reverse().toString();
    }
}

Excel表序列化(A->1)

class Solution {
    public int titleToNumber(String s) {
        int ret = 0;
        char[] chars = s.toCharArray();
        for(char ch : chars) {
            int temp = ch - 'A' + 1;
            ret = ret * 26 + temp;
        }
        return ret;
    }
}

字符串转整数

https://leetcode-cn.com/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/

class Solution {
    public int strToInt(String str) {
    	//先去空格再判空,不然" "教您做人,血的教训
        str = str.trim();
        if(str.length() == 0){
            return 0;
        }
        //然后我想啊,下面要判断首位了
        //首位合格的无非就'+'或'-'或数字三种情况,其他的一概滚蛋
        //'+''-'肯定是要把它去掉的,这样三种情况就统一了
        //当然了,'-abc'这种有可能出现,不过只看首位它是没毛病的
        //让它进来,反正后面很容易解决
        //既然要去掉正负号,那肯定要出个boolean记一下是不是负数
        boolean isMinus = false;
        char[] ch = str.toCharArray();
        //首位是不是正负号或者数字啊
        if(ch[0] == '+' || ch[0] == '-' || Character.isDigit(ch[0])){
        	//是不是正负号啊
            if(ch[0] == '+' || ch[0] == '-'){
            	//是不是负号啊
                if(ch[0] == '-'){
                    isMinus = true;
                }
                //删除首位
                ch = Arrays.copyOfRange(ch,1,ch.length);
            }
            //首位搞定了就看后面是不是数字了,直到不是数字的地方或者倒底结束
            int index = 0;
            //结果可能超int范围,拿个long接一下
            //'-abc'这种情况返回的也是0,舒服,一箭双雕
            long res = 0;
            //短路与助您远离空指针喔,铁汁们,先后顺序关注一下
            while(index < ch.length && Character.isDigit(ch[index])){
                //一位一位往上算
                res *= 10;
                res += ch[index] - '0';
                //及时止损,一看到res超int范围立马return
                //你要是想着最后一起算,那肯定会有超long范围的测试用例等着你,你就哭去吧
                if(res > Integer.MAX_VALUE){
                    //正负号看是正数负数,返回最大值
                    return isMinus ? Integer.MIN_VALUE : Integer.MAX_VALUE;
                }
                //别忘了往后走一位
                index++;
            }
            //long转int就是这么朴实无华
            return isMinus ? -(int)res : (int)res;
        }
        //兄弟首位都不对想啥呢,回去吧您
        return 0;
    }
}

用两个栈实现队列

https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/

class CQueue {
private Stack<Integer> s1=new Stack<>();
    private Stack<Integer> s2=new Stack<>();

    public CQueue() {

    }
    
    public void appendTail(int value) {
         s1.push(value);
    }
    
    public int deleteHead() {

        if(s1.isEmpty()&&s2.isEmpty())
        {
            return -1;
        }
        if(!s2.isEmpty())
        {
            return s2.pop();
        }else{
            while(!s1.isEmpty())
            {
                s2.push(s1.pop());
            }
            return s2.pop();
        }
    }
}

包含min函数的栈

https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/

class MinStack {

    /** initialize your data structure here. */
    Stack<Integer> s1 = new Stack<>();
    Stack<Integer> s2 = new Stack<>();
    public MinStack() {
        
    }
    
    public void push(int x) {
        s1.push(x);
        if(s2.isEmpty() || x <= s2.peek()) {
            s2.push(x);
        }
    }
    
    public void pop() {
        if(s1.peek().equals(s2.peek())) {
            s1.pop();
            s2.pop();
        }else{
            s1.pop();
        }
    }
    
    public int top() {
        return s1.peek();
    }
    
    public int min() {
        return s2.peek();
    }
}

数组中重复的数字

class Solution {
    public int findRepeatNumber(int[] nums) {
        if(nums == null || nums.length == 0) {
            return -1;
        }
        for(int i = 0; i < nums.length; i++) {
            for(int j = i + 1; j < nums.length; j++ ) {
                if(nums[i] == nums[j]) {
                    return nums[i];
                }
            }
        }
        return -1;
    }
}

二维数组中额的查找

https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/

public class Solution {
    public boolean Find(int target, int [][] arr) {
         if(arr == null || arr.length == 0) {
            return false;
        }
        int i = 0, j = arr[0].length - 1;
        while(i < arr.length && j >= 0) {
            if(arr[i][j] > target) {
                j--;
            }else if(arr[i][j] < target) {
                i++;
            }else {
                return true;
            }
        }
        return false;
    }
}

0~n-1中缺失的数字

https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof/

class Solution {
    public int missingNumber(int[] nums) {
        if(nums == null || nums.length == 0) {
            return -1;
        }
        int l = 0;
        int r = nums.length - 1;
        while(l < r) {
            int mid = l + r >> 1;
            if(nums[mid] != mid) {
                r = mid;
            }else {
                l = mid + 1;
            }
        }
        if(nums[l] == l) {
            l++;
        }
        return l;
    }
}

二维数组中查找

核心思路:二分

public class Solution {
    public boolean Find(int target, int [][] array) {
        if(array == null || array.length == 0 ) {
            return false;
        }
        int i = 0;
        int j = array[0].length - 1;
        while(i < array.length && j >= 0)
        {
            if(array[i][j] > target)
            {
                j--;
            }else if(array[i][j] < target) {
                i++;
            }else {
                return true;
            }
        }
        return false;
    }
}

替换空格

  • 解法一: 调用replace库函数
import java.util.*;
public class Solution {
    public String replaceSpace (String s) {
        // write code here
        return s.replace(" ","%20");
    }
}
  • 解法二: 遍历,逐个修改

import java.util.*;
 
public class Solution {

    public String replaceSpace (String s) {
        if (s == null || s.length() == 0)
            return "";
            StringBuilder ret = new StringBuilder();
            for(char x : s.toCharArray()){
                if(x != ' ') {
                    ret.append(x + "");
                }else {
                    ret.append("%20");
                }
            }
        return ret.toString();
    }
}

从头到尾打印链表

  • 解法一:将链表反转一下,再逐个打印输出即可
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> ret = new ArrayList<>();
    //反转链表
    public void reverse(ListNode head) {
        ListNode cur = head, curNext = null, prev = null;
        while(cur != null) {
            curNext = cur.next;
            cur.next = prev;
            prev = cur;
            cur = curNext;
        }
        while(prev != null) {
            ret.add(prev.val);
            prev = prev.next;
        }
    }
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        if(listNode == null) return ret;
        reverse(listNode);
        return ret;
    }
}
  • 解法二:利用栈
import java.util.*;
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> ret = new ArrayList<>();
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        if(listNode == null) return ret;
        Stack<Integer> stk = new Stack<>();
        ListNode cur = listNode;
        while(cur != null) {
            stk.push(cur.val);
            cur = cur.next;
        }
        while(!stk.isEmpty()) {
            ret.add(stk.pop());
        }
        return ret;
    }
}

重建二叉树(根据前序遍历和中序遍历来构建二叉树)

public class Solution {
    public int preIndex = 0;
    //根据前序遍历递归重建
    public TreeNode dfs(int[] pre, int[] in, int l, int r) {
        if(l > r) return null;
        TreeNode root = new TreeNode(pre[preIndex]);
        int index = findVal(in, pre[preIndex], l, r);
        preIndex++;
        root.left = dfs(pre, in, l, index - 1);
        root.right = dfs(pre, in, index + 1, r);
        return root;
    }
    //查找元素在中序遍历中的位置
    public int findVal(int[] in, int key, int l, int r) {
        for(int i = l; i <= r; i++) {
            if(in[i] == key ){
                return i;
            }
        }
        return -1;
    }
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        if(pre == null || in == null) return null;
        return dfs(pre, in, 0 , in.length - 1);
    }
}

这道题还有两道类似的题目,根据中序遍历和后续遍历构造二叉树根据前序遍历和后续遍历构造二叉树

用两个栈实现队列

  • 核心思路:一个栈s1代表入队列,另一个栈s2代表出队列
import java.util.Stack;

public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
        stack1.push(node);  
    }
    
    public int pop() {
        if(stack1.isEmpty() && stack2.isEmpty())
        {
            return -1;
        }
        if(!stack2.isEmpty())
        {
            return stack2.pop();
        }else{
            while(!stack1.isEmpty())
            {
                stack2.push(stack1.pop());
            }
            return stack2.pop();
        }
    }
}

旋转数组的最小数字

  • 核心思路:二分
import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] nums) {
        if(nums == null || nums.length == 0) return -1;
        int n = nums.length  - 1;
        while(n > 0 && nums[0] == nums[n]) n--;
        if(nums[n] > nums[0]) return nums[0];
        int l = 0, r = n;
        while(l < r) {
            int mid = l + r >> 1;
            if(nums[mid] < nums[0]){
                r = mid;
            }else {
                l = mid + 1;
            }
        }
        return nums[l];
    }
}

菲波那切数列

  • 解法一: 递归
public class Solution {
    public int Fibonacci(int n) {
        if(n < 2) return n;
        return Fibonacci(n - 1) + Fibonacci(n - 2);
    }
}
  • 解法二: 迭代
public class Solution {
    public int Fibonacci(int n) {
        if(n < 2) return n;
        int f1 = 0, f2 = 0, f3 = 1;
        for(int i = 2; i <= n; i++) {
            f1 = f2;
            f2 = f3;
            f3 = f1 + f2;
        }
        return f3;
    }
}
  • 解法三:动态规划
class Solution {
    public int fib(int n) {
        if(n < 2) return n;
        int [] arr = new int[n + 1];
            arr[0] = 0;
            arr[1] = 1;
        for (int i = 2; i <= n; i++) {
            arr [i] = arr[i - 2] + arr[i - 1];
        }
        return arr[n];
    }
}

菲波那切数列(取模)

dp


class Solution {
    public int fib(int n) {
        if(n == 0) return 0;
        int[] dp = new int[n + 1];
        dp[0] = 0;
        dp[1] = 1;
        for(int i = 2; i <= n; i++){
            dp[i] = dp[i-1] + dp[i-2];
            dp[i] %= 1000000007;
        }
        return dp[n];
    }
}

迭代

class Solution {
    public int fib(int n) {
    if(n==0)
        return 0;
    if(n==1)
        return 1;

    int num1=0,num2=1,sum=0;
    while(n>=2){
        sum=(num1+num2)%1000000007 ;//题目要求
        num1=num2;
        num2=sum;
        n--;
    }
    return sum;
        }  
}

爬楼梯

迭代

public class Solution {
    public int jumpFloor(int n) {
        if(n <= 2) {
            return n;
        }
        int f1 = 0;
        int f2 = 1;
        int f3 = 2;
        for(int i = 3; i <= n; i++) {
            f1 = f2;
            f2 = f3;
            f3 = f2 + f1;
        }
        return f3;
    }
}

动态规划

public class Solution {
    public int jumpFloor(int n) {
        if(n < 2) {
            return 1;
        }
        int[] arr = new int[n + 1];
        arr[0] = 1;
        arr[1] = 1;
        for(int i = 2; i <= n; i++) {
            arr[i] = arr[i - 1] + arr[i - 2];
        }
        return arr[n];
    }
}

跳台阶

迭代

public class Solution {
    public int jumpFloor(int n) {
        if(n <= 2) {
            return n;
        }
        int f1 = 0;
        int f2 = 1;
        int f3 = 2;
        for(int i = 3; i <= n; i++) {
            f1 = f2;
            f2 = f3;
            f3 = f2 + f1;
        }
        return f3;
    }
}

动态规划

public class Solution {
    public int jumpFloor(int n) {
        if(n < 2) {
            return 1;
        }
        int[] arr = new int[n + 1];
        arr[0] = 1;
        arr[1] = 1;
        for(int i = 2; i <= n; i++) {
            arr[i] = arr[i - 1] + arr[i - 2];
        }
        return arr[n];
    }
}

跳台阶扩展问题

核心思路:
手把手带你刷剑指offer_第1张图片

public class Solution {
    public int jumpFloorII(int target) {
        if(target < 2) {
            return 1;
        }
        int[] arr = new int[target + 1];
        arr[1] = 1;
        for(int i = 2; i <= target; i++) {
            arr[i] = 2 * arr[i - 1];
        }
        return arr[target];
    }
}

矩阵覆盖

核心思路

递归实现

public class Solution {
    public int rectCover(int target) {
        if(target < 1) {
            return 0;
        }else if(target <= 2) {
            return target;
        }else {
            return rectCover(target - 1) + rectCover(target - 2);
        }
    }
}

迭代实现

public class Solution {
    public int rectCover(int target) {
        if(target < 1) {
            return 0;
        }else if(target <= 2) {
            return target;
        }
        int f1 = 1;
        int f2 = 2;
        int f3 = 0;
        for(int i = 3; i <= target; i++){
            //f3先更新
            f3 = f1 + f2;
            f1 = f2;
            f2 = f3;
            
            
        }
        return f3;
    }
}

动态规划实现

public class Solution {
    public int rectCover(int target) {
        if(target < 1) {
            return 0;
        }else if(target <= 2) {
            return target;
        }
        int[] arr = new int[target + 1];
        arr[0] = 1;
        arr[1] = 1;
//         int ret = 0;
        for(int i = 2; i <= target; i++) {
            arr[i] = arr[i - 1] + arr[i - 2];
        }
        return arr[target];
    }
}

二进制中一的个数

这个就非常经典啦

public class Solution {
    public int NumberOf1(int n) {
        int count = 0;
        while(n != 0) {
            n = n & (n - 1);
            count++;
        }
        return count;
    }
}

数值的整数次方

核心思路:快速幂

public class Solution {
    public double Power(double x, int n) {
        if(x == 0) {
            return 0;
        }
        long b = n;
        double ret = 1.0;
        if(b < 0) {
            x = 1 / x;
            b = -b;
        }
        while(b > 0) {
            if((b & 1) == 1) {
                ret *= x;
            }
            x *= x;
            b >>= 1;
        }
        return ret;
  }
}

调整数组顺序使奇数位于偶数前面

import java.util.*;


    public int[] reOrderArray (int[] array) {
        // write code here
        if(array.length == 0){
            return array;
        }
         Queue<Integer> odd = new LinkedList<>();
        Queue<Integer> even = new LinkedList<>();
        for(int i = 0;i < array.length ;i++){
            if(array[i] % 2 != 0){
                odd.add(array[i]);
            }else{
                even.add(array[i]);
            }
        }
        int[] ret = new int[array.length];
        for(int i = 0; i < array.length; i++){
            if(!odd.isEmpty()){
                ret[i] = odd.poll();
            }else{
                ret[i] = even.poll();
            }
        }
        return ret;
    }
}

public int[] reOrderArray (int[] array) {
    int index = 0;
    int[] res = new int[array.length];
    for (int i : array) {
        if (i % 2 != 0) {
            res[index] = i;
            index++;
        }
    }
    for (int i : array) {
        if (i % 2 == 0) {
            res[index] = i;
            index++;
        }
    }
    return res;
}

链表中倒数第k个结点

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    public ListNode FindKthToTail (ListNode pHead, int k) {
        // write code here
        if(pHead == null) return null;
        ListNode fast = pHead, slow = pHead;
        for(int i = 0; i < k ; i++) {
            if(fast == null) {
                return null;
            }else {
                fast = fast.next;
            }          
        }
        while(fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

反转链表

public class Solution {
    public ListNode ReverseList(ListNode head) {
        if(head == null) return null;
        ListNode prev = null, cur = head, curNext = null;
        while(cur != null) {
            curNext = cur.next;
            cur.next = prev;
            prev = cur;
            cur = curNext;
        }
        return prev;
    }
}

合并两个有序链表

public class Solution {
    public ListNode Merge(ListNode l1,ListNode l2) {
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        ListNode newHead = new ListNode(-1);
        ListNode tmp = newHead;
        while(l1 != null && l2 != null) {
            if(l1.val <= l2.val) {
                tmp.next = l1;              
                l1 = l1.next;
            }else {
                tmp.next = l2;                
                l2 = l2.next;
            }
            tmp = tmp.next;
        }
        if(l1 == null) {
            tmp.next = l2;
        }
        if(l2 == null) {
            tmp.next = l1;
        }     
        return newHead.next;
    }
}

树的子结构

public class Solution {
    public boolean HasSubtree(TreeNode s,TreeNode t) {
      if(s == null|| t == null) return false;
      if(isSametree(s,t)) return true;
      if(HasSubtree(s.left, t)) return true;
      if(HasSubtree(s.right, t)) return true;
      return false;
    }
    public boolean isSametree(TreeNode p, TreeNode q) {
        if(q == null) return true;
        if(p == null) return false;
        if(p.val != q.val) return false;
        return isSametree(p.left, q.left) && isSametree(p.right, q.right);
    }
}

二叉树的镜像

  • DFS
public class Solution {

    public TreeNode Mirror (TreeNode pRoot) {
        // write code here
        if(pRoot == null) return null;
        TreeNode rootLeft = Mirror(pRoot.right);
        TreeNode rootRight = Mirror(pRoot.left);
        pRoot.left = rootLeft;
        pRoot.right = rootRight;
        return pRoot;
    }
}
  • BFS
public class Solution {
    public TreeNode Mirror (TreeNode root) {
        // write code here
        if(root == null) return null;
        Stack<TreeNode> stack = new Stack<>();
        stack.add(root);
        while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            if(node.left != null) stack.add(node.left);
            if(node.right != null) stack.add(node.right);
            TreeNode tmp = node.left;
            node.left = node.right;
            node.right = tmp;
        }
        return root;
        
        
    }
}

从上往下打印二叉树

import java.util.ArrayList;
import java.util.*;
public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
       Queue<TreeNode> queue = new LinkedList<>();
       ArrayList<Integer> ret = new ArrayList<>();
       if(root == null) return ret;
        queue.offer(root);
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if(node.left != null) queue.offer(node.left);
            if(node.right != null) queue.offer(node.right);
             ret.add(node.val);
        }
        return ret;
    }
}

复杂链表的复刻

核心思路:hashmap

import java.util.*;
public class Solution {
    public RandomListNode Clone(RandomListNode head) {
        HashMap<RandomListNode, RandomListNode> map = 
            new HashMap<>();
        RandomListNode cur = head;
        while(cur != null) {
            RandomListNode node = new RandomListNode(cur.label);
            map.put(cur, node);
            cur = cur.next;
        }
        cur = head;
        while(cur != null) {
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return map.get(head);
    }
}

二叉搜索树和双向链表

public class Solution {
    TreeNode prev = null;
    public void inorder(TreeNode root) {
        if(root == null) return ;
        inorder(root.left);
        root.left = prev;
        if(prev != null) {
            prev.right = root;
        }
        prev = root;
        inorder(root.right);
    }
    
    public TreeNode Convert(TreeNode root) {
        if(root == null) return null;
        inorder(root);
        TreeNode head = root, tail = root;
        while(head.left != null) {
            head = head.left;
        }
        while(head.right != null) {
            tail = tail.right;
        }
        head.left = tail;
        tail.right = head;
        return head;
        
    }
}

两个链表的第一个公共节点

public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
         ListNode p = pHead1, q = pHead2;
          while(p != q) {
              if(p !=  null) {
                  p = p.next;
              }else {
                  p = pHead2;
              }
              
              if(q != null) {
                  q = q.next;
              }else {
                  q = pHead1;
              }
          }
        return p;
    }
}

链表中环的入口节点

public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        ListNode fast = pHead, slow = pHead;
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow) {
                break;
            }
        }
        if(fast == null || fast.next == null) {
            return null;
        }
        slow = pHead;
        while(fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
        
    }
}

删除链表中重复的节点

public class Solution {
    public ListNode deleteDuplication(ListNode head)
    { 
        if(head == null) return null;
        ListNode cur = head;
        ListNode newHead = new ListNode(-1);
        ListNode tmp = newHead;
        while(cur != null) {
            if(cur.next != null && cur.val == cur.next.val) {
                while(cur.next != null && cur.val ==cur.next.val){
                    cur = cur.next;
                }
                cur = cur.next;
            }else {
                tmp.next = cur;
                tmp = tmp.next;
                cur = cur.next;
            }
             tmp.next = null;
        }
        return newHead.next;
    }
}

两数相加

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        int carray = 0;
        ListNode head = null, tail = null;
        while(l1 != null || l2 != null) {
            int n1 = l1 != null ? l1.val : 0;
            int n2 = l2 != null ? l2.val : 0;
            int sum = n1 + n2 + carray;
            if(head == null) {
                head = tail = new ListNode(sum % 10);
            }else {
                tail.next = new ListNode(sum % 10);
                tail = tail.next;
            }
            carray = sum / 10;
            if(l1 != null) {
                l1 = l1.next;
            }
            if(l2 != null) {
                l2 = l2.next;
            }
        }
        if(carray > 0) {
            tail.next = new ListNode(carray);
        }
        return head;
    }
}

二叉树的镜像

public class Solution {
    public TreeNode Mirror (TreeNode root) {
        // write code here
        if(root == null) {
            return null;
        }
        TreeNode left = Mirror(root.left);
        TreeNode right = Mirror(root.right);
        root.left = right;
        root.right = left;
        return root;
    }
}

对称二叉树

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null) {
            return true;
        }
        return dfs(root.left, root.right);

    }
    public boolean dfs(TreeNode r1, TreeNode r2) {
        if(r1 == null && r2 == null) {
            return true;
        }
        if(r1 == null  || r2 == null) {
            return false;
        }
        return r1.val == r2.val && dfs(r1.left, r2.right) && dfs(r1.right, r2.left);
    }
}

按之字形顺序打印二叉树

import java.util.ArrayList;
import java.util.*;

public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode root) {
        ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
        if(root == null) {
            return ret;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            ArrayList<Integer> tmp = new ArrayList<>();
            for(int i = queue.size(); i > 0; i--) {
                TreeNode node = queue.poll();
                if(ret.size() % 2 == 0) {
                    tmp.add(node.val);
                }else {
                    tmp.add(0,node.val);
                }
                if(node.left != null){
                    queue.offer(node.left);
                }
                if(node.right != null) {
                    queue.offer(node.right);
                }
            }
            ret.add(tmp);
        }
       return ret;
    }
}

数组中的逆序对

public class Solution {
    public int InversePairs(int [] nums) {
        if(nums == null || nums.length == 0) {
            return -1;
        }
        return mergeSort(nums, 0, nums.length - 1);
    }
        public int mergeSort(int[] arr, int l, int r) {
        if(l >= r) {
            return 0;
        }
        int mid = l + r >> 1;
        int ret = mergeSort(arr, l, mid) + mergeSort(arr, mid + 1, r);
          int[] tmp = new int[r - l + 1];
        int k = 0;
        int i = l, j = mid + 1;
        while(i <= mid && j <= r) {
            if(arr[i] <= arr[j]) {
                tmp[k++] = arr[i++];
            }else {
                tmp[k++] = arr[j++];
                ret += mid - i + 1;
            }
        }
        while(i <= mid) tmp[k++] = arr[i++];
        while(j <= r) tmp[k++] = arr[j++];
        for(i = l,j = 0; i <= r; i++, j++) {
            arr[i] = tmp[j];
        }
        return ret;
    }
}

和为s的两个数字

class Solution {
    public int[] twoSum(int[] nums, int target) {
          if(nums == null || nums.length == 0) {
            return null;
        }
        int i = 0, j = nums.length - 1;
        while(i < j) {
            int sum = nums[i] + nums[j];
            if(sum < target) {
                i++;
            }else if(sum > target) {
                j--;
            }else {
                return new int[]{nums[i],nums[j]};
            }
        }
        return new int[0];
    }
}

滑动窗口最大值

https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums == null || nums.length == 0) {
            return new int[0];
        }
        int[] res = new int[nums.length - k + 1];
        Deque<Integer> queue = new ArrayDeque<>();
        for(int i = 0, j = 0; i < nums.length; i++) {
            if(!queue.isEmpty() && i - queue.peek() >= k) {
                queue.poll();
            }
            //保证队头存的一定是最大的值
            while(!queue.isEmpty() && nums[i] > nums[queue.peekLast()]) {
                queue.pollLast();
            }
            queue.offer(i);
            if(i >= k - 1) {
                res[j++] = nums[queue.peek()];
            }
        }
        return res;
    }
}

把数组排成最小的数

https://leetcode-cn.com/submissions/detail/202910965/

class Solution {
    public String minNumber(int[] nums) {
         String[] strs = new String[nums.length];
        for(int i = 0; i < nums.length; i++) {
            strs[i] = String.valueOf(nums[i]);
        }
        Arrays.sort(strs, (x, y)-> (x + y).compareTo(y + x));
        StringBuffer ret = new StringBuffer();
        for(String s : strs) {
            ret.append(s);
        }
        return ret.toString();
    }
}

表达式求值

https://www.nowcoder.com/practice/c215ba61c8b1443b996351df929dc4d4?tpId=117&&tqId=37849&&companyId=665&rp=1&ru=/company/home/code/665&qru=/ta/job-code-high/question-ranking

import java.util.*;


public class Solution {
    public int solve (String s) {
        // write code here
        if(s == null) return 0;
        Stack<Integer> numStack= new Stack<>();
        Stack<Character> opStack= new Stack<>();
        for(int i=0;i<s.length();i++){
            //处理数字栈
            if(s.charAt(i)>='0'&&s.charAt(i)<='9'){
                if(i==0){
                    numStack.add(s.charAt(i)-'0');
                }else{
                    if(s.charAt(i-1)>='0'&&s.charAt(i)<='9'){
                        int tmp=numStack.pop();
                        int num=tmp*10+(s.charAt(i)-'0');
                        numStack.add(num);
                    }else{
                        numStack.add(s.charAt(i)-'0');
                    }
                }
            }else{
                //处理符号栈
                if(opStack.isEmpty()){
                    opStack.add(s.charAt(i));
                }else{
                    if(s.charAt(i) == '('){
                        opStack.push(s.charAt(i));
                    }else if(s.charAt(i) == ')'){
                        while(opStack.peek() != '('){
                            cal(numStack, opStack.pop());
                        }
                        opStack.pop();
                    }else if(s.charAt(i) == '*'){
                        if(opStack.peek() == '*'){
                             cal(numStack, opStack.pop());
                        }
                        opStack.push(s.charAt(i));
                    }else if(s.charAt(i) == '+' || s.charAt(i) == '-'){
                        if(opStack.peek() != '('){
                            cal(numStack, opStack.pop());
                        }
                        opStack.push(s.charAt(i));
                    }
                }
            }
        }
        while(!opStack.isEmpty()){
            cal(numStack,opStack.pop());
        }
        return numStack.pop();
    }
    public void cal(Stack<Integer> stackInt, char ope){
        int x = stackInt.pop();
        int y = stackInt.pop();
        if(ope == '*'){
            stackInt.push(x * y);
        }else if(ope == '+'){
            stackInt.push(x + y);
        }else if(ope == '-'){
            stackInt.push(y - x);
        }
    }
}

持续更新中。。。。。。。

你可能感兴趣的:(LeetCode,剑指Offer,leetcode)