部分leetcode题目

1)字符串升序旋转
2)LRU实现
3)给定一个非空的整数数组,返回其中出现频率前 k 高的元素
4)36进制加法
5)数组中出现次数超过数组一半的数字

一:

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4

示例 2:输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1

package com.lzg.flume.intercepter;

public class SearchInRotatedSortedArray {
    // 1 最外层的mid 跟 target进行比较
    // 2 数组只可能是这两种类型// 456789123  // 789123456 进行比较
    public int search(int[] nums, int target) {
        if (nums == null || nums.length <= 0) {
            return -1;
        }
        int len = nums.length;
        int start = 0;
        int end = len - 1;
        while (start <= end) {
            int mid = (start + end) >> 1;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] > target){
                // mid在左侧递增大区间
                if (nums[mid] > nums[end]) {// 456789123
                    // 目标值大于最右侧值,左侧寻找
                    if (target > nums[end]) {
                        end = mid - 1;
                        // 否则右侧寻找
                    } else {
                        start = mid + 1;
                    }
                    // mid在小区间, 此时mid又大于target,向左侧寻找
                } else {// 789123456
                    end = mid - 1;
                }
            } else {
                // mid在左侧递增大区间
                if (nums[mid] > nums[end]) {// 456789123
                    // 右侧寻找
                    start = mid + 1;
                    // mid在小区间, 此时mid又小于target
                } else { // 789123456
                    if (target > nums[end]) {
                        // 左侧寻找
                        end = mid - 1;
                        // 否则右侧寻找
                    } else {
                        start = mid + 1;
                    }
                }
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] nums = {4,5,6,7,0,1,2};
        System.out.println(new SearchInRotatedSortedArray().search(nums, 0));
        System.out.println(new SearchInRotatedSortedArray().search(nums, 3));
    }

}

题目二:Java实现LRU缓存

方法1:LRU Cache的链表+HashMap实现

class Node {
    public int key, val;
    public Node next, prev;
    public Node(int k, int v) {
        this.key = k;
        this.val = v;
    }
}


class DoubleList {  
    // 在链表头部添加节点 x,时间 O(1)
    public void addFirst(Node x);

    // 删除链表中的 x 节点(x 一定存在)
    // 由于是双链表且给的是目标 Node 节点,时间 O(1)
    public void remove(Node x);
    
    // 删除链表中最后一个节点,并返回该节点,时间 O(1)
    public Node removeLast();
    
    // 返回链表长度,时间 O(1)
    public int size();
}

class LRUCache {
    // key -> Node(key, val)
    private HashMap<Integer, Node> map;
    // Node(k1, v1) <-> Node(k2, v2)...
    private DoubleList cache;
    // 最大容量
    private int cap;
    
    public LRUCache(int capacity) {
        this.cap = capacity;
        map = new HashMap<>();
        cache = new DoubleList();
    }
    
    public int get(int key) {
        if (!map.containsKey(key))
            return -1;
        int val = map.get(key).val;
        // 利用 put 方法把该数据提前
        put(key, val);
        return val;
    }
    
    public void put(int key, int val) {
        // 先把新节点 x 做出来
        Node x = new Node(key, val);
        
        if (map.containsKey(key)) {
            // 删除旧的节点,新的插到头部
            cache.remove(map.get(key));
            cache.addFirst(x);
            // 更新 map 中对应的数据
            map.put(key, x);
        } else {
            if (cap == cache.size()) {
                // 删除链表最后一个数据
                Node last = cache.removeLast();
                map.remove(last.key);
            }
            // 直接添加到头部
            cache.addFirst(x);
            map.put(key, x);
        }
    }
}

 

方法2:LRU Cache的LinkedHashMap实现

public class LRUCache3<K, V> {

    private final int MAX_CACHE_SIZE;
    private final float DEFAULT_LOAD_FACTOR = 0.75f;
    LinkedHashMap<K, V> map;

    public LRUCache3(int cacheSize) {
        MAX_CACHE_SIZE = cacheSize;
        //根据cacheSize和加载因子计算hashmap的capactiy,+1确保当达到cacheSize上限时不会触发hashmap的扩容,
        int capacity = (int) Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTOR) + 1;
        map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTOR, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry eldest) {
                return size() > MAX_CACHE_SIZE;
            }
        };
    }

    public synchronized void put(K key, V value) {
        map.put(key, value);
    }

    public synchronized V get(K key) {
        return map.get(key);
    }

    public synchronized void remove(K key) {
        map.remove(key);
    }

    public synchronized Set<Map.Entry<K, V>> getAll() {
        return map.entrySet();
    }

    public synchronized int size() {
        return map.size();
    }

    public synchronized void clear() {
        map.clear();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry entry : map.entrySet()) {
            sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
        }
        return sb.toString();
    }
}

 

题目三:

 * 给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
 * 示例 1:
 * 输入: nums = [1,1,1,2,2,3], k = 2
 * 输出: [1,2]
 * 示例 2:
 * 输入: nums = [1], k = 1
 * 输出: [1]
 * 说明:
 * 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
 * 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

方法1优先队列(利用优先队列进行排序,排序到第k个值之后,每次都取头上的最小数值跟剩下的依次比较,如果比最小的大就放入优先队列中。注意优先队列一直保持为k个数值)
public List<Integer> topKFrequent(int[] nums, int k) {
        final HashMap<Integer, Integer> map = new HashMap<>();
        //用map统计各个元素都有多少个
        for (int num : nums) {
            if (map.containsKey(num)) {
                map.put(num, map.get(num) + 1);
            } else {
                map.put(num, 1);
            }
        }
        //用优先队列获得最多的前K个
        PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
            public int compare(Integer a, Integer b) {
                // 出现次数少的在前
                return map.get(a) - map.get(b);
            }
        });

        for (int key : map.keySet()) {
            // 控制队列元素数量
            if (queue.size() < k) {
                queue.add(key);
                continue;
            }

            // 队列中元素达到 K 值 ,去除最小值比较
            int small = queue.peek();
            if (map.get(small) < map.get(key)) {
                queue.poll();
                queue.add(key);
            }
        }
        return new ArrayList<Integer>(queue);
    }


方法2:桶排序(以数组中某个数字的个数作为bucket的index)

public List<Integer> topKFrequent2(int[] nums, int k) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            if (map.containsKey(num)) {
                map.put(num, map.get(num) + 1);
            } else {
                map.put(num, 1);
            }
        }

        // 创建 nums.length + 1 个桶
        List<Integer>[] bucket = new List[nums.length + 1];
        // 遍历map,根据value值 出现的次数 放到对应的桶中
        for (Map.Entry<Integer, Integer> e : map.entrySet()) {

            Integer value = e.getValue();
            if (bucket[value] == null) {
                bucket[value] = new ArrayList<>();
            }

            bucket[value].add(e.getKey());
        }

        List<Integer> freList = new ArrayList<>();
        // 桶的编号表示出现次数,所以倒数桶
        for (int j = bucket.length - 1; j > -1 && freList.size() < k; j--) {

            if (bucket[j] != null)
                freList.addAll(bucket[j]);
        }
        return freList;
    }
 

四 36进制加法

36进制由0-9,a-z,共36个字符表示,最小为'0'
'0''9'对应十进制的09,'a''z'对应十进制的1035
例如:'1b' 换算成10进制等于 1 * 36^1 + 11 * 36^0 = 36 + 11 = 47
要求按照加法规则计算出任意两个36进制正整数的和
如:按照加法规则,计算'1b' + '2x' = '48'

要求:不允许把36进制数字整体转为10进制数字,计算出10进制数字的相加结果再转回为36进制

思路:

创建一个字符串,

string nums = "0123456789abcdefghijklmnopqrstuvwxyz";


找到两个字符串相加字母  在  字符串nums 中的位置, 这个位置就是字母所表示的大小,例如z:35.  a:10

然后用位置相加,如果相加的结果超过36,则进位;否则不进位。

最后把剩下的字符串加到保存的结果中,翻转结果即可。

package com.lzg.flume.intercepter;

public class Plus6 {
    public static String nums = "0123456789abcdefghijklmnopqrstuvwxyz";
    public static String plus(String s1, String s2){
        int i = s1.length()-1;
        int j = s2.length()-1;
        int temp =0;
        StringBuilder sb = new StringBuilder();
        while(i>=0&&j>=0){
            char c1= s1.charAt(i);
            char c2= s2.charAt(j);
            int index1 = nums.indexOf(c1);
            int index2 = nums.indexOf(c2);
            int sum = index1+index2+temp;
            if(sum>=36){
                temp=1;
                sb.append(nums.charAt(sum%36));
            }else{
                temp = 0;
                sb.append(nums.charAt(sum%36));
            }
            i--;
            j--;
        }
        while(i>=0){
            char c1 = s1.charAt(i);
            int index1 = nums.indexOf(c1);
            int sum = temp+index1;
            if(sum>=36){
                temp=1;
                sb.append(nums.charAt(sum%36));
            }else{
                temp=0;
                sb.append(nums.charAt(sum%36));
            }
            i--;
        }
        while(j>=0){
            char c2 = s2.charAt(j);
            int index2 = nums.indexOf(c2);
            int sum = temp+index2;
            if(sum>=36){
                temp=1;
                sb.append(nums.charAt(sum%36));
            }else{
                temp=0;
                sb.append(nums.charAt(sum%36));
            }
            j--;
        }
        if(temp!=0){
            sb.append("1");
        }
        sb.reverse();
        return sb.toString();
    }

    public static void main(String[] args) {
        String s1= "1z";
        String s2= "1";
        System.out.println(plus(s1,s2));
    }
}

五:数组中出现次数超过数组一半的数字

方法一:使用哈希表对数组每个数字进行遍历,Map<nums的某个值,出现次数>,当出现次数超过数组一半返回该数。
方法二:若一个数字出现的次数超过数组长度的一半,则该数字减去其他数字个数必定大于0,根据这个原理,使用摩尔法投票法,记录一个数字,遍历数组,若是该数,票数加一,不是减一,为零下次出现什么都投一票,记录值变为下次出现的值。最后,记录中必定是出现过半的数字!

class Solution {
    public int majorityElement(int[] nums) {
        if (nums.length == 1) return nums[0];
        int half = nums.length >> 1;
        int count;
        Map<Integer, Integer> myMap = new HashMap<>();
        for (int x = nums.length - 1; x > -1; x--) {
            if (myMap.containsKey(nums[x])) {
                count = myMap.get(nums[x]);
                if (++count >= half) {
                    return nums[x];
                }
                myMap.remove(nums[x]);
                myMap.put(nums[x], count++);
            } else {
                myMap.put(nums[x], 1);
            }
        }
        return -1;
    }
}

方法2
 

class Solution {
    public int majorityElement(int[] nums) {
        int result = nums[0];
        int count = 0;
        for (int x : nums) {
            if (count == 0) {
                count++;
                result = x;
            }
            else {
                count+=(x==result)?1:-1;
            }
        }
        return result;
    }
}

 

 

 

 

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值