高频率面试编程题

高频率面试编程题

面试题 17.14. 最小K个数

美团面试的时候,写随机快排,quicksort函数的quicksort(array,left,index - 1)写错成quicksort(array,left,index)导致stackoverflowerror

解法1:快排

import java.util.*;
class Solution {
    public int[] smallestK(int[] arr, int k) {
        int[] answer = new int[k];
        quicksort(arr,0,arr.length - 1);
        for(int i = 0;i < k;i ++) {
            answer[i] = arr[i];
        }
        return answer;
    }
    
    public void quicksort(int[] array,int left,int right) {
        if(left < right) {
            int index = partition(array,left,right);
            //quicksort(array,left,index);
            quicksort(array,left,index - 1);
            quicksort(array,index + 1,right);
        }
    }
    public int partition(int[] array,int left,int right) {
        Random random = new Random();
        int flag = random.nextInt(right - left + 1) + left;
        int pivot = array[flag];
        //swap(array,flag,array.length - 1);
        swap(array,flag,right);
        //int pivot = array[flag];
        int index = left - 1;
        for(int i = left;i <= right;i ++) {
            if(array[i] <= pivot) {
                index ++;
                swap(array,index,i);
            }
        }
        return index;
    }
    //java函数交换数组的两个数字可以,单独交换两个数字不可以,类似传参与传引用
    public void swap(int[] array,int i,int j) {
        int tem = array[i];
        array[i] = array[j];
        array[j] = tem;
    }
}

解法2:实现堆排序

待实现

剑指 Offer 45. 把数组排成最小的数

解法:

注意:

1.new 一个比较器的时候,new Comparator<> (T) {重写的compare方法},T是代表一个类型,其实就是泛型,不能是int,long,float,得是Integer,Float,Long等对应的包装类型。但是int[],long[],float[]可以。

        Arrays.sort(nums1,new Comparator() {

            public int compare(Integer a,Integer b) {

                return a * 10 + b - b * 10 + a;

            }

        });

2.对于本题,比较器是比较两个数,比如30和3,是303大还是330大,因此使用Integer数组不方便,两个数的位数不一样,因此使用String的数组,“30” + “3”可以直接拼接,拼接之后(“30” + “3”).compareTo("3" + "30");用String.valueOf()这个静态方法(重载的,建议)可以得到数字对应的String。

3.另外,可以有String类型的数组不可以有Stringbuilder和StringBuffer类型的数组,虽然创建StringBuilderStringBuffer的数组不报错,但是数组的内容就不能改变了,个人认为如果改变,不符合数组的内存地址连续性。

4.Comparator与Comparable:

https://blog.csdn.net/weixin_34066347/article/details/85621968

https://blog.csdn.net/qq_40693828/article/details/81409004?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.channel_param

 

class Solution {
    public String minNumber(int[] nums) {
        //
		/*
		Integer[] nums1 = new Integer[nums.length];
		for(int i = 0; i < nums.length;i ++) {
			nums1[i] = new Integer(nums[i]);
		}
        StringBuilder sb = new StringBuilder();
        Arrays.sort(nums1,new Comparator() {
            public int compare(Integer a,Integer b) {
                return a * 10 + b - b * 10 + a;
            }
        });
        */
		String[] nums1 = new String[nums.length];
		for(int i = 0; i < nums.length;i ++) {
			nums1[i] = String.valueOf(nums[i]);
		}
        StringBuilder sb = new StringBuilder();
        Arrays.sort(nums1,new Comparator() {
            public int compare(String a,String b) {
                //return Integer.parseInt(a + b) - Integer.parseInt(b + a);
                return (a + b).compareTo((b + a));
            }
        });
        for(int i = 0;i < nums1.length;i ++) {
            sb.append(nums1[i]);
        }
        return sb.toString();
    }
}

215. 数组中的第K个最大元素

解法:PriorityQueue是用堆实现的

待完成:用数组实现堆

class Solution {
    public int findKthLargest(int[] nums, int k) {
        if(k > nums.length){
            return 0;
        }
        /*
        PriorityQueue minHeap = new PriorityQueue<>(nums.length,(a,b) -> a - b);
        
        for(int i = 0;i < nums.length;i ++){
            minHeap.add(nums[i]);
        }
        for(int i = 0;i < nums.length - k;i ++){
            minHeap.poll();
        }
        return minHeap.peek();
        */
        PriorityQueue minHeap = new PriorityQueue<>(k,(a,b) -> a - b);
        for(int i = 0;i < k;i ++){
            minHeap.add(nums[i]);
        }
        for(int i = k;i < nums.length;i ++){
            if(nums[i] > minHeap.peek()){
                minHeap.poll();
                minHeap.add(nums[i]);
            }
        }
        return minHeap.peek();
    }
}

3. 无重复字符的最长子串

解法:这是滑动窗口系列题目之一

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.length() <= 1){
            return s.length();
        }
        HashMap map = new HashMap<>();
        int left = 0;
        int max = 0;
        for(int i = 0;i < s.length();i ++){
            if(map.containsKey(s.charAt(i))){
                //更新left的时候与i无关
                left = Math.max(map.get(s.charAt(i)) + 1,left);
            }
            //更新max
            max = Math.max(max,i - left + 1);
            //添加map
            map.put(s.charAt(i),i);
        }
        return max;
    }
}

24. 两两交换链表中的节点

class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode ans = reserveN(head,2);
        
        ans.next.next = swapPairs(ans.next.next);
        return ans;
    }
    ListNode lastofnext = null;
    //从head节点开始反转N个链表
    public ListNode reserveN(ListNode head,int N){
        if(N == 1){
            lastofnext = head.next;
            return head;
        }
        //last是指向反转后头节点的指针,因此应返回last
        ListNode last = reserveN(head.next,N - 1);
        head.next.next = head;
        head.next = lastofnext;
        //返回的是last而不是head
        return last;
    }
}

128. 最长连续序列

解法:使用HashSet,符合题意的最长递增子序列的开始数字X,set里肯定不包含X - 1

比如最长的递增子序列是 2 3  4,那么1肯定不能在数组和set里。

class Solution {
    public int longestConsecutive(int[] nums) {
        if(nums.length <= 1) {
            return nums.length;
        }else {
            HashSet set = new HashSet<>();
            int answer = 1;
            int currentlength;
            int currentnumber;
            for(int i = 0;i < nums.length;i ++) {
                set.add(nums[i]);
            }
            for(int i = 0;i < nums.length;i ++) {
                //点睛之处,对于数N,如果N - 1也在set里,那么最长的递增序列一定不是从N开始的,
                //最长的递增序列,开始的数字X,set里肯定没有X - 1
                if(! set.contains(nums[i] - 1)) {
                    currentlength = 1;
                    currentnumber = nums[i];
                    while(set.contains(currentnumber + 1)) {
                        currentlength ++;
                        currentnumber ++;
                    }
                    answer = Math.max(answer,currentlength);
                }
                
            }
            return answer;
        }
    }
}

151. 翻转字符串里的单词

解法:一般会问递归的解法。

class Solution {
    StringBuilder sb;
    public String reverseWords(String s) {
        sb = new StringBuilder();
        //第一个单词变成最后一个单词,因此第一个单词加入sb的时候,不加空格
        getReverseWord(sb,s,0,false);
        return sb.toString();
    }
    //把单词存储到sb中,left表示从s的下标left开始添加下一个单词,flag表示在sb后面添加单词之后,sb后面还要不要加空格,原来的第一个单词加入sb之后,sb后面不需要加了
    public void getReverseWord(StringBuilder sb,String s,int left,boolean flag) {
        while(left < s.length() && s.charAt(left) == ' ') {
            left ++;
        }
        //left指向下一个单词的开始字母,或者left等于s.length()
        if(left == s.length()) {
            return;
        }
        int right = left;
        //right指向空格(left指向那个单词之后的第一个空格)或者right等于s.Length()
        while(right < s.length() && s.charAt(right) != ' ') {
            right ++;
        }
        getReverseWord(sb,s,right,true);
        //下面可以代替上面的for循环,
        //sb.append(s.substring(left,right));
        //为什么是小于right?因为right没有指向单词的字母
        
        for(int i = left;i < right;i ++) {
            sb.append(s.charAt(i));
        }
        
        if(flag) {
            sb.append(' ');
        }
    }
}

38. 外观数列

解法:迭代,很明显n个外观数需要依靠第n-1个外观数得到

class Solution {
    public String countAndSay(int n) {
         if(n == 1){
             return "1";
         }else{
            String before = countAndSay(n - 1);
            StringBuilder sb = new StringBuilder();
            int index = 0;
            while(index < before.length()){
                int counter = 1;
                char character = before.charAt(index);
                while(index + 1 < before.length()  && before.charAt(index + 1) == character){
                    index ++;
                    counter ++;
                }
                sb.append(counter);
                sb.append(character);
                index ++;
            }
            return sb.toString();
         }
    }
}

886. 可能的二分法

class Solution {
    //
    public ArrayList[] graph;
    //点如果涂颜色,就加入map
    public HashMap map;
    //0代表红色,1代表蓝色
    public boolean possibleBipartition(int N, int[][] dislikes) {
        graph = new ArrayList[N + 1];
        map = new HashMap();
        for(int i = 0;i <= N;i ++){
            graph[i] = new ArrayList();
        }
        //graph[i]表示i + 1不能共存的链表
        for(int i = 0;i < dislikes.length;i ++){
            graph[dislikes[i][0]].add(dislikes[i][1]);
            graph[dislikes[i][1]].add(dislikes[i][0]);
        }
        for(int i = 1;i <= N;i ++){
            if(! map.containsKey(i) && ! dfs(i,0)){
                return false;
            }
        }
        return true;
    }
    //把node的节点涂成color,是否合理
    public boolean dfs(int node,int color){
        //如果node已经存在,判断node的值与color是否相同
        if(map.containsKey(node)){
            return map.get(node) == color;
        }
        //如果不含有key
        map.put(node,color);
        for(int i = 0;i < graph[node].size();i ++){
            //^是逐位 
            if(! dfs(graph[node].get(i),color ^ 1)){
                return false;
            }
        }
        return true;
    }
}

322. 零钱兑换

解法:待实现:贪心+二分查找+动态规划,也就是先尽量换大的零钱

class Solution {
    public int coinChange(int[] coins, int amount) {
        if(amount == 0){
            return 0;
        }
        //dp[i]代表凑成i元,需要的硬币个数
        int[] dp = new int[amount + 1];

        Arrays.sort(coins);
        for(int i = 0;i < coins.length && coins[i] <= amount;i ++){
            dp[coins[i]] = 1;
        }
        if(dp[amount] != 0){
            return dp[amount];
        }

        for(int i = coins[0];i <= amount;i ++){
            if(dp[i] == 1){
                continue;
            }else{
                //下面的超时间
                /*
                int min = Integer.MAX_VALUE;
                for(int j = coins[0];j <= i - coins[0];j ++){
                    if(dp[j] != 0 && dp[i - j] != 0){
                        min = Math.min(min,dp[j] + dp[i - j]);
                    }
                }
                if(min == Integer.MAX_VALUE){
                    dp[i] = 0;
                }else{
                    dp[i] = min;
                }
                */
                int min = Integer.MAX_VALUE;
                for(int j = 0;j < coins.length && coins[j] <= i;j ++){
                    if(dp[i - coins[j]] != 0){
                        min = Math.min(dp[coins[j]] + dp[i - coins[j]],min);
                    }
                    
                }
                dp[i] = min == Integer.MAX_VALUE ? 0 : min;
            }
        }
        //System.out.println(dp[10]);
        return dp[amount] == 0 ? -1 : dp[amount];
    }
    public int find(int[] array,int target){
        return 1;
    }
}
class Solution {
    public int coinChange(int[] coins,int amount) {
        if(amount == 0){
            return 0;
        }
        int[] dp =new int[amount + 1];
        //第一个不一样的地方
        Arrays.fill(dp,amount + 1);
        //循环计算dp[i]
        //第二个不一样的地方
        dp[0] = 0;
        //金钱的循环再外面,否则会出现重复的情况
        for(int coin : coins){
            for(int i = coin;i <= amount;i ++){
                //第三个不一样的地方
                dp[i] = Math.min(dp[i],dp[i - coin] + 1);
            }
        }
        //第四个不一样的地方
        return dp[amount] == amount + 1 ? -1 : dp[amount];
    }
}

518. 零钱兑换 II

解法:类似与爬楼梯问题

class Solution {
    //类似于爬楼梯
    public int change(int amount, int[] coins) {
        if(amount == 0){
            return 1;
        }
        int[] dp =new int[amount + 1];
        //循环计算dp[i]
        dp[0] = 1;
        //金钱的循环再外面,否则会出现重复的情况
        for(int coin : coins){
            for(int i = coin;i <= amount;i ++){
                //相当于爬楼梯问题
                //dp[n] = dp[n - 1] + dp[n - 2]
                dp[i] += dp[i - coin];
            }
        }
        return dp[amount];
    }
}

739. 每日温度

解法:递减栈

class Solution {
    //递减栈的思想
    public int[] dailyTemperatures(int[] T) {
        if(T.length <= 1){
            return new int[T.length];
        }else{
            //存储数据并不方便,因为还要得到数组下标,因此不如直接存储下标
            Stack stack = new Stack<>();
            int[] answer = new int[T.length];
            for(int i = 0;i < T.length;i ++){
                while(! stack.isEmpty() && T[i] > T[stack.peek()]){
                    answer[stack.peek()] = i - stack.peek();
                    stack.pop();
                }
                stack.push(i);
            }
            return answer;
        }
    }
}

406. 根据身高重建队列

解法:见注释

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        //按照身高递减,身高相同排名递增的顺序重新排列二维数组
        Arrays.sort(people,new Comparator(){
            public int compare(int[] a,int[] b){
                return a[0] == b[0] ? a[1] - b[1] : b[0] - a[0];
            }
        });
        List list = new LinkedList<>();
        for(int[] p : people){
            //在list的指定下标插入数据
            list.add(p[1],p);
        }
        return list.toArray(new int[people.length][2]);
    }
}

面试题 16.25. LRU缓存

解法:HashMap+LinkedList

HashMap表示key是否存在,LinkedList模拟队列

class LRUCache {
    public int capacity;
    public HashMap map;
    public LinkedList list;
    public LRUCache(int capacity) {
        this.capacity = capacity;
        map = new HashMap<>();
        list = new LinkedList<>();
    }
    
    public int get(int key) {
        //
        if(map.containsKey(key)){
            /*
            //使用就把key从list中取出来加到队尾
            int index = 0;
            for(int i = 0;i < list.size();i ++){
                if(list.get(i) == key){
                    index = i;
                    break;
                }
            }
            list.remove(index);
            list.addLast(key);
            */
            //应该注意remove(index)和remove(Object key)的区别
            //这里不能直接remove(key)
            list.remove((Integer) key);
            list.addLast(key);
            return map.get(key);
        }else{
            return  -1;
        }
    }
    
    public void put(int key, int value) {
        //如果有key存在也触发使用条件
        if(map.containsKey(key)){
            list.remove((Integer) key);
            list.addLast(key);
            map.put(key,value);
        }else if(list.size() < capacity){
            //长度小于capacity可以put
            map.put(key,value);
            list.addLast(key);
        }else{
            map.remove(list.getFirst());
            list.removeFirst();
            map.put(key,value);
            list.addLast(key);
        }
    }
}

836. 矩形重叠

解法:降维,把问题看作XY两个方向的区间合并,不同的是,区间只相交一个点不算相交

class Solution {
    public boolean isRectangleOverlap(int[] rec1, int[] rec2) {
        if(rec1.length != 4 || rec2.length != 4){
            throw new IllegalArgumentException();
        }else{
            
            int[] array1 = {rec1[0],rec1[2]};
            int[] array2 = {rec2[0],rec2[2]};
            int[] array3 = {rec1[1],rec1[3]};
            int[] array4 = {rec2[1],rec2[3]};
            if(judge(array1,array2) && judge(array3,array4)){
                return true;
            }else{
                return false;
            }
        }
    }
    //降维
    public boolean judge(int[] array1,int[] array2){
        if(array1.length != 2 || array2.length != 2){
            return false;
        }else{
            
            if(array1[0] <= array2[0]){
                //根据题意等于不对
                if(array1[1] > array2[0]){
                    return true;
                }
            }else{
                if(array2[1] > array1[0]){
                    return true;
                }
            }
            return false;
        }
    }
}

9. 回文数

解法1:双指针,Integer.toString(int x)可以把x转化为String

class Solution {
    public boolean isPalindrome(int x) {
        if(x < 0){
            return false;
        }else if(x < 10){
            return true;
        }else{
            String number = Integer.toString(x);
            int left = 0;
            int right = number.length() - 1;
            while(left < right){
                if(number.charAt(left) != number.charAt(right)){
                    return false;
                }else{
                    left ++;
                    right --;
                }
            }
            return true;
        }
    }
}

解法2:数学的方法模拟双指针

class Solution {
    public boolean isPalindrome(int x) {
        if(x < 0){
            return false;
        }else if(x < 10){
            return true;
        }else{
            int div = 1;
            int tem = x;
            //必须是大于等于10
            while(tem >= 10){
                tem = tem / 10;
                div *= 10;
            }
            //System.out.println(div);
            //x >= 10不对,无法解决1000021的情况
            while(x > 0){
                int left = x % 10;
                int right = x / div;
                if(left != right){
                    return false;
                }else{
                    //原来的x除去最高位和最低位
                    x = (x % div) / 10;
                    div = div / 100;
                }
            }
            return true;
        }
    }
}

43. 字符串相乘

解法:1.字符串反转,让最低位是个位;2.num1 * num2 = answer,由于999 * 999 = 998901,answer数组的长度是num1的长度加上num2的长度即可。不考虑进位:answer[i+j] += num1[i] * num2[j] =;最后统一进位。

class Solution {
    public String multiply(String num1, String num2) {
        //999*999=998001
        //x位的数乘以y位的数,结果肯定是x+y位的数
        if(num1 == null){
            return num2;
        }else if(num2 == null){
            return num1;
        }else if(num1.equals("0") || num2.equals("0")){
            //不应该用==,应该用.equals()
            return "0";
        }else{
            int[] answer = new int[num1.length() + num2.length()];
            /*
            int number1;
            int number2;
            */
            //经过反转之后,个位在0
            num1 = reverse(num1);
            num2 = reverse(num2);
            for(int i = 0;i < num1.length();i ++){
                for(int j = 0;j < num2.length();j ++){
                    //最后统一进位
                    answer[i + j] += ((num1.charAt(i) - '0') * (num2.charAt(j) - '0'));
                    /*
                    answer[i + j] += (number1 * number2) % 10;
                    answer[i + j + 1] += (number1 * number2) / 10;
                    */
                }
            }
            //统一进位,注意一个是等于一个是加等于,并且顺序不能反
            for(int i = 0;i < answer.length - 1;i ++){
                /*
                answer[i] = answer[i] % 10;
                answer[i + 1] += answer[i] / 10;
                */
                answer[i + 1] += answer[i] / 10;
                answer[i] = answer[i] % 10;
            }
            StringBuilder sb = new StringBuilder();
            int i = 0;
            for(i = answer.length - 1;i >= 0;i --){
                if(answer[i] != 0){
                    break;
                }
            }
            for(;i >= 0;i --){
                sb.append(answer[i]);
            }
            return sb.toString();
        }
    }
    //反转字符串函数
    public String reverse(String num){
        if(num == null){
            return null;
        }else{
            StringBuilder sb = new StringBuilder();
            for(int i = num.length() - 1;i >= 0;i --){
                sb.append(num.charAt(i));
            }
            return sb.toString();
        }
    }
}

[牛客网编程题]链表中环的入口节点

解法:快慢指针+双指针,剑指offer23,链表中环的入口节点

//解法:快慢指针+双指针
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode node = getNode(head);
        //面试写的时候,就是忘记判断node == null,导致NullPointerException
        if(node == null) {
            return null;
        }else {
            ListNode answer = head;
            int length = getLength(node);
            //让front先向前走length步,answer和front一起往后一次走一步
            ListNode front = head;
            for(int i = 0;i < length;i ++) {
                front = front.next;
            }
            while(answer != front) {
                answer = answer.next;
                front = front.next;
            }
            return answer;
        }
    }
    //如果有环,得到环的长度
    public int getLength(ListNode node) {
        int answer = 1;
        ListNode tem = node.next;
        while(node != tem) {
            answer ++;
            tem = tem.next;
        }
        return answer;
    }
    //快慢指针,返回的要么是环中的节点,要么是null
    public ListNode getNode(ListNode head) {
        if(head == null) {
            return null;
        }else {
            ListNode fast = head.next;
            ListNode slow = head;
            while(fast != null && fast.next != null) {
                if(fast == slow) {
                    return fast;
                }
                slow = slow.next;
                
                fast = fast.next.next;
            }
            return null;
        }
    }
}

268. 缺失数字

解法:1+...+n减去nums数组之和,但是直接求nums数组之和,可能会int溢出。

class Solution {
    //直接求nums数组的和可能会溢出
    public int missingNumber(int[] nums) {
        if(nums.length == 0){
            throw new IllegalArgumentException();
        }else{
            int sum = 0;
            for(int i = 0;i < nums.length;i ++){
                sum += nums[i];
            }
            return nums.length * (nums.length + 1) / 2 - sum;
        }
    }
}
class Solution {
    //直接求nums数组的和可能会溢出
    public int missingNumber(int[] nums) {
        if(nums.length == 0){
            throw new IllegalArgumentException();
        }else{
            /*
            int sum = 0;
            for(int i = 0;i < nums.length;i ++){
                sum += nums[i];
            }
            return nums.length * (nums.length + 1) / 2 - sum;
            */
            //原理和上面的一样,但是避免了int溢出
            int result = 0;
            for(int i = 1;i <= nums.length;i ++){
                result += i - nums[i - 1];
            }
        }
    }
}

67. 二进制求和

解法:存储答案的Stringbuilder的先存储个位,并且两个数都从低位相加

class Solution {
    //存储答案的Stringbuilder的先存储
    public String addBinary(String a, String b) {
        if(b == null || b.equals("0")){
            return a;
        }else if(a == null || a.equals("0")){
            return b;
        }else{
            int index1 = a.length() - 1;
            int index2 = b.length() - 1;
            int number = 0;
            int sum = 0;
            StringBuilder sb = new StringBuilder();
            while(index1 >= 0 && index2 >= 0){
                sum = number + (a.charAt(index1) - '0') + (b.charAt(index2) - '0');
                number = sum / 2;
                sb.append(sum % 2);
                index1 --;
                index2 --;
            }
            while(index1 >= 0){
                sum = (a.charAt(index1) - '0') + number;
                number = sum / 2;
                sb.append(sum % 2);
                index1 --;
            }
            while(index2 >= 0){
                sum = (b.charAt(index2) - '0') + number;
                number = sum / 2;
                sb.append(sum % 2);
                index2 --;
            }
           
            if(number != 0){
                sb.append(number);
            }
            return sb.reverse().toString();
        }
    }
}

268. 缺失数字

异或运算的思路见解析:https://leetcode-cn.com/problems/missing-number/solution/que-shi-shu-zi-by-leetcode/

class Solution {
    //异或是逐位异或的,比如0^3=3
    public int missingNumber(int[] nums) {
        int answer = 0;
        for(int i = 0;i < nums.length;i ++){
            answer ^= (i ^ nums[i]);
        }
        return answer ^ nums.length;
    }
}

20. 有效的括号

解法:哔哩哔哩笔试题,原来用动态规划写的,动态规划不适合{}{}{}()情况,只适合{({[]})}情况,应该用栈。

class Solution {
    public boolean isValid(String s) {
        if(s.length() == 0){
            return true;
        }else if(s.length() % 2 == 1) {
            return false;
        }else {
            HashMap map = new HashMap<>();
            map.put(')','(');
            map.put('}','{');
            map.put(']','[');
            Stack stack = new Stack<>();
            for(int i = 0;i < s.length();i ++){
                char c = s.charAt(i);
                if(! map.containsKey(c)){
                    stack.push(c);
                }else{
                    if(! stack.isEmpty() && stack.peek() == map.get(c)){
                        stack.pop();
                    }else{
                        return false;
                    }
                }
            }
            return stack.isEmpty();
            /*
            map.put('(',1);
            map.put(')',-1);
            map.put('[',2);
            map.put(']',-2);
            map.put('{',3);
            map.put('}',-3);
            Stack stack = new Stack<>();
            for(int i = 0;i < s.length();i ++){
                if(! map.containsKey(s.charAt(i))){
                    return false;
                }else if(map.get(s.charAt(i)) > 0){
                    stack.push(s.charAt(i));
                }else{
                    if(! stack.isEmpty() 
                    && (map.get(s.charAt(i)) + map.get(stack.peek()) == 0)){
                        stack.pop();
                    }else{
                        return false;
                    }
                }
            }
            
            if(stack.isEmpty()){
                return true;
            }else{
               return false; 
            }
            */
        }
    }
}

189. 旋转数组

时间复杂度题目要求O(n),空间复杂度O(1)

解法1:反转数组,因此本题改成反转链表也是可以的。

k = k % nums.length,先反转[0,nums.length - 1],再反转[0,k - 1]和[k,nums.length - 1]

class Solution {
    public void rotate(int[] nums, int k) {
        if(nums.length <= 1){
            return;
        }else{
            //忘记写下面一句
            k = k % nums.length;
            reverse(nums,0,nums.length - 1);
            reverse(nums,0,k -1);
            reverse(nums,k,nums.length - 1);
        }
    }
    public void reverse(int[] nums,int left,int right){
        int tem = 0;
        //当left = right的情况下,循环结束
        //当一开始的时候,left = right,不需要反转
        while(left < right){
            tem = nums[left];
            nums[left] = nums[right];
            nums[right] = tem;
            //忘记写下面的两句了
            left ++;
            right --;
        }
    }
}

解法2:https://leetcode-cn.com/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode/

class Solution {
    public void rotate(int[] nums, int k) {
        if(nums.length <= 1 || k < 1){
            return;
        }else{
            //忘记写下面一句
            k = k % nums.length;
            //counter表示已经交换的个数
            int counter = 0;
            int index = 0;
            int start = 0;
            int pre;
            int tem = 0;
            while(counter < nums.length){
                index = start;
                pre = nums[start];
                do{
                    int next = (index + k) % nums.length;
                    tem = nums[next];
                    nums[next] = pre;
                    pre = tem;
                    index = next;
                    next = (next + k) % nums.length;
                    counter ++;
                } while(index != start);
                start = (start + 1) % nums.length;
            }
        }
    }
}

409. 最长回文串

解法:哈希表

class Solution {
    public int longestPalindrome(String s) {
        if(s.length() == 0 && s.length() == 1) {
            return s.length();
        }else {
            HashMap map = new HashMap<>();
            int answer = 0;
            for(int i = 0;i < s.length();i ++) {
                if(map.containsKey(s.charAt(i))) {
                    map.put(s.charAt(i), map.get(s.charAt(i)) + 1);
                }else {
                    map.put(s.charAt(i), 1);
                }
            }
            for(char key : map.keySet()){
                answer += map.get(key) % 2;
            }
            return answer == 0 ? s.length() : s.length() - answer + 1;
        }
    }   
}

110. 平衡二叉树

解法:类似于337. 打家劫舍 III

class Solution {
    //flag表示题目所给的树是不是平衡二叉树,其值为false就表示不是平衡二叉树
    boolean flag = true;
    public boolean isBalanced(TreeNode root) {
        if(root == null) {
            return true;
        }else {
            //最终目的不是为了获得dp函数的返回值,因此直接调用即可
            dp(root);
            return flag;
        }
    }
    //dp函数返回的数组,第一个元素表示左子树的高
    //第二个元素表示右子树的高
    public int[] dp(TreeNode root) {
        int[] answer = new int[2];
        //root为空直接返回
        //flag为false,表示题目中的树的子树已经失衡,直接返回即可
        if(root == null || flag == false) {
            return answer;
        }else {
            int[] left = dp(root.left);
            int[] right = dp(root.right);
            if(get(left[0],left[1]) > 1 || get(right[0],right[1]) > 1){
                flag = false;
            }
            answer[0] = Math.max(left[0],left[1]) + 1;
            answer[1] = Math.max(right[0],right[1]) + 1;
            if(get(answer[0],answer[1]) > 1){
                flag = false;
            }
            return answer;
        }
    }
    public int get(int a,int b){
        return Math.abs(a - b);
    }
}

剑指 Offer 30. 包含min函数的栈

解法:辅助栈和数据栈,两个栈包含元素的数量一直一样

class MinStack {
    //辅助栈存储的元素的多少每时每刻都和数据栈一样
    //辅助栈的栈顶元素对应数据栈从栈底到栈顶的最小值
    public Stack datastack;
    public  Stack helpstack;
    /** initialize your data structure here. */
    public MinStack() {
        this.datastack = new Stack<>();
        this.helpstack = new Stack<>();
    }
    
    public void push(int x) {
        //加入辅助栈的条件:1.辅助栈为空或者x小于辅助栈栈顶元素
        //2.否则,也就是辅助栈不为空并且栈顶元素小于x,那么辅助栈加入栈顶元素
        if(helpstack.isEmpty() || x < helpstack.peek()) {
            helpstack.push(x);
        }else {
            helpstack.push(helpstack.peek());
        }
        //加入数据栈
        datastack.push(x);
    }
    
    public void pop() {
        if(! datastack.isEmpty() && ! helpstack.isEmpty()) {
            datastack.pop();
            helpstack.pop();
        }
    }
    
    public int top() {
        return datastack.peek();
    }
    
    public int min() {
        return helpstack.peek();
    }
}

剑指 Offer 39. 数组中出现次数超过一半的数字

解法:设置一个counter = 1和number  = nums[0],往后遍历,当遍历得到的数字等于number,counter ++;否则counter --。如果counter == 0,那么number = 当前遍历的数字,counter重新设置为1.

class Solution {
    public int majorityElement(int[] nums) {
        if(nums.length == 0) {
            throw new IllegalArgumentException();
        }else if(nums.length == 1) {
            return nums[0];
        }else {
            int counter = 1;
            int number = nums[0];
            for(int i = 1;i < nums.length;i ++) {
                if(nums[i] == number) {
                    counter ++;
                }else {
                    counter --;
                }
                if(counter == 0) {
                    number = nums[i];
                    counter = 1;
                }
            }
            return number;
        }
    }
}

 

你可能感兴趣的:(高频率面试编程题)