每天一道算法题leetcode

很佩服面试出leetcode题的人。。。。。。老子不刷题,刷不完。。。写的不对就给你挂掉的人,牛逼。。。

腾讯面试体验最好,引导候选人一点点写。

https://leetcode-cn.com/problemset/all/

 

这个哥哥总结的很好

https://blog.csdn.net/weixin_33991418/article/details/91810578

股票交易日

在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行)。给出一天中的股票变化序列,请写一个程序计算一天可以获得的最大收益。请采用实践复杂度低的方法实现。

给定价格序列prices及它的长度n,请返回最大收益。保证长度小于等于500。

如下:

[10, 22, 5, 75, 65, 80], 6

返回:

87

风口的猪

风口之下,猪都能飞。当今中国股市牛市,真可谓“错过等七年”。 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示,数组中第i个元素(prices[i])代表该股票第i天的股价。

假设你一开始没有股票,但有至多两次买入1股而后卖出1股的机会,并且买入前一定要先保证手上没有股票。若两次交易机会都放弃,收益为0。 设法计算你能获得的最大收益。 输入数值范围:2<=n<=100,0<=prices[i]<=100

输入:

[3, 8, 5, 1, 7, 8] 6

返回:

12

 

public class 风口的猪 {
    public static void main(String[] args) {
//        int[] dataSet = {10, 22, 5, 75, 65, 80};
        int[] dataSet = {3, 8, 5, 1, 7, 8};
        int result = maxProfit(dataSet, dataSet.length);
        System.out.println(result);
    }

    public static int maxProfit(int[] dataSet, int n) {
        int sum = 0;
        for (int i = 0; i < dataSet.length; i++) {
            int tmp = getMax(dataSet, 0, i - 1) + getMax(dataSet, i, dataSet.length - 1);
            if (tmp > sum) {
                sum = tmp;
            }
        }
        return sum;
    }

    private static int getMax(int[] dataSet, int left, int right) {
        if (left >= right) {
            return 0;
        }
        int min = dataSet[left];
        int max = 0;
        for (int i = left; i <= right; i++) {
            if (dataSet[i] - min > max) {
                max = dataSet[i] - min;
            }
            if (dataSet[i] < min) {
                min = dataSet[i];
            }
        }
        return max;
    }
}

 

最长公共字串

求两个字符串的最长公共子串,如“abcdefg”和“adefgwgeweg”的最长公共子串为“defg”(子串必须是连续的)

import com.sun.deploy.util.StringUtils;

import java.util.List;

public class 最长公共子串 {
        public static void main(String[] args) {
            String str1 = "abcdefg";
            String str2 = "adefgwgeweg";
            System.out.println(getMaxSubString(str1, str2));
        }

        public static List getMaxSubString(String str1, String str2) {
            if (StringUtils.isEmpty(str1) || StringUtils.isEmpty(str2)) {
                return null;
            }

            String max;
            String min;
            if (str1.length() > str2.length()) {
                max = str1;
                min = str2;
            } else {
                max = str2;
                min = str1;
            }

            List subStrings = Lists.newArrayList();
            String maxSubString = StringUtils.EMPTY;
            for (int i = 0; i < min.length(); i++) {
                for (int begin = 0, end = min.length() - i; begin < end; begin++) {
                    String tmp = min.substring(begin, end);
                    if (max.contains(tmp) && tmp.length() >= maxSubString.length()) {
                        maxSubString = tmp;
                        subStrings.add(maxSubString);
                    }
                }
            }
            return subStrings;
        }
    }

 

最大公约数和最小公倍数

public class 最大公约数和最小公倍数 {
    public static void main(String[] args) {
        int m = 8;
        int n = 12;
        System.out.println(maxCommonDivisor(m, n) + " " + minCommonMultiple(m, n));
    }

    public static int maxCommonDivisor(int m, int n) {
        if (m < n) {
            int tmp = m;
            m = n;
            n = tmp;
        }
        while (n != 0) {
            int tmp = m % n;
            m = n;
            n = tmp;
        }
        return m;
    }

    public static int minCommonMultiple(int m, int n) {
        return m * n / maxCommonDivisor(m, n);
    }
}

 

字典序列化

我们程序中用到了一个数组 a ,数组的每个元素都是一个字典(map/dict)。

字典的 key/value 都是字符串,字符串中可包含任意字符。

示例:

    a[0]["k1"] = "v1"

    a[0]["k2"] = "v2"

    a[1]["A"] = "XXX"

    ...

实际使用过程中,我们自定义了一个基于字符串的存储结构,数组元素之间用“换行”分割,

字典元素之间使用“分号”分割, key/value 之间用“等号”分割。

上述数据序列化之后,应该得到一个字符串:

    "k1=v1;k2=v2\nA=XXX"

请实现一个“保存”函数、一个“加载”函数。

    text = store(a); //把数组保存到一个字符串中

    a = load(text);  //把字符串中的内容读取为字典数组

请考虑所有边界情况,不要出现bug。在满足上述需求的前提下,可自行增加一些规则和约定。

 

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class 字典序列化 {
        /**
         *
         */
        private static final long serialVersionUID = -546082353499911945L;
        public static void main(String[] args) {
            List> map = new  ArrayList>();
            // TODO Auto-generated method stub
//            字典序列化 dictArr = new 字典序列化();


            Map element = new HashMap<>();
            element.put("k1", "v1");
            element.put("k2", "v2");

            map.add(element);
            element = new HashMap<>();
            element.put("A", "XXX");
            map.add(element);

            String rt = store(map);
            load(rt);
        }

        /**
         *
         * @return
         */
        public static String store(List> map) {
            String str = "";

            for(int i=0;i item = map.get(i);
                for(Map.Entry entry:item.entrySet()){
                    String k = entry.getKey();
                    String v = entry.getValue();
                    str += (k + "="+v+";");
                }
                str = str.substring(0, str.length()-1);
                str+="\\n";
            }

            str = str.substring(0, str.length()-2);
            System.out.println("结果为---->        "+str.toString());
            return str;
        }

        /***
         *
         * @param dictArrayText
         * @return
         */
        public static List> load(String dictArrayText) {
            String elements[] = dictArrayText.split("\\\\n");
            List> map = new  ArrayList>();
            for(String element:elements) {

                String kvs[] = element.split(";");
                Map dic = new HashMap<>();
                for(String kv:kvs) {

                    String kvPair[] = kv.split("=");
                    dic.put(kvPair[0], kvPair[1]);
                }
                map.add(dic);
            }
            return map;
        }

}

 

路径规划

我们有一个有向无环图,权重在节点上。

需求:从一个起点开始,找到一条节点权重之和最大的最优路径。

输入: n个节点,m个路径,起点

输出: 最优路径的权重值之和

举例:

    3个节点与权重: A=1, B=2, C=2

    3条路径: A->B, B->C, A->C

    起点: A

    输出: 5 (最优路径是 A->B->C , 权重之和是 1+2+2=5)

请考虑算法效率优化,考虑异常情况(比如输入的图有环路)要避免死循环或者崩溃。

import java.util.List;
import java.util.Map;

public class 路径规划 {
    public static void main(String[] args) {
        String[] vertex = {"a", "b", "c", "d", "e"};
        int[] weight = {0, 1, 1, 3, 6};
        double[][] matrix = {
                {0, 1, 0, 1, 0},
                {0, 0, 1, 0, 0},
                {0, 0, 0, 0, 1},
                {0, 0, 0, 0, 1},
                {0, 0, 0, 0, 0}};

        Graph graph = new Graph<>(matrix, vertex, weight);
        System.out.println(graph.getMinWeight(graph.startSearch()));
    }

    public static class Graph {
        // 邻接矩阵
        private double[][] matrix;
        // 顶点数组
        private String[] vertex;
        // 顶点数组对应权重值
        private int[] weight;
        // 顶点的数目
        private int vertexNum;
        // 当前结点是否还有下一个结点,判断递归是否结束的标志
        private boolean noNext = false;
        // 所有路径的结果集
        private List> result = Lists.newArrayList();

        public Graph(double[][] matrix, String[] vertex, int[] weight) {
            if (matrix.length != matrix[0].length) {
                throw new IllegalArgumentException("该邻接矩阵不是方阵");
            }
            if (matrix.length != vertex.length) {
                throw new IllegalArgumentException("结点数量和邻接矩阵大小不一致");
            }
            if (vertex.length != weight.length) {
                throw new IllegalArgumentException("邻接矩阵大小和权重值数量不一致");
            }
            this.matrix = matrix;
            this.vertex = vertex;
            this.weight = weight;
            vertexNum = matrix.length;
        }

        /**
         * 深度遍历的递归
         */
        private void DFS(int begin, List path) {
            // 将当前结点加入记录队列
            path.add(vertex[begin]);
            // 标记回滚位置
            int rollBackNum = -1;
            // 遍历相邻的结点
            for (int i = 0; i < vertexNum; i++) {
                if ((matrix[begin][i] > 0)) {
                    // 临时加入相邻结点,试探新的路径是否已遍历过
                    path.add(vertex[i]);
                    if (containBranch(result, path)) {
                        // 路径已存在,将相邻结点再移出记录队伍
                        path.remove(vertex[i]);
                        // 记录相邻点位置,用于循环结束发现仅有当前一个相邻结点时回滚事件
                        rollBackNum = i;
                        // 寻找下一相邻结点
                        continue;
                    } else {
                        // 路径为新路径,准备进入递归,将相邻结点移出记录队伍,递归中会再加入,防止重复添加
                        path.remove(vertex[i]);
                        // 递归
                        DFS(i, path);
                    }
                }
                // 终止递归
                if (noNext) {
                    return;
                }
            }
            if (rollBackNum > -1) {
                // 循环结束仅有一个相邻结点,从这个相邻结点往下递归
                DFS(rollBackNum, path);
            } else {
                // 当前结点没有相邻结点,设置flag以结束递归
                noNext = true;
            }
        }

        /**
         * 开始深度优先遍历
         */
        public List> startSearch() {
            for (int i = 0; i < countPathNumber(); i++) {
                // 用于存储遍历过的点
                List path = new LinkedList<>();
                noNext = false;
                // 开始遍历
                DFS(0, path);
                // 保存结果
                result.add(path);
            }
            return result;
        }

        /**
         * 获取权重值最大的路径
         */
        public MaxWeight getMaxWeight(List> lists) {
            Map weightMap = Maps.newHashMap();
            for (int i = 0; i < vertex.length; i++) {
                weightMap.put(vertex[i], weight[i]);
            }
            int max = 0;
            int index = 0;
            for (int i = 0; i < lists.size(); i++) {
                int w = 0;
                for (String str : lists.get(i)) {
                    w += weightMap.get(str);
                }
                if (w > max) {
                    max = w;
                    index = i;
                }
            }
            return new MaxWeight(lists.get(index), max);
        }

        /**
         * 获取权重值最小的路径
         */
        public MaxWeight getMinWeight(List> lists) {
            Map weightMap = Maps.newHashMap();
            for (int i = 0; i < vertex.length; i++) {
                weightMap.put(vertex[i], weight[i]);
            }
            int min = 0;
            int index = 0;
            for (int i = 0; i < lists.size(); i++) {
                int w = 0;
                for (String str : lists.get(i)) {
                    w += weightMap.get(str);
                }
                if (min == 0) {
                    min = w;
                    index = i;
                }
                if (w < min) {
                    min = w;
                    index = i;
                }
            }
            return new MaxWeight(lists.get(index), min);
        }

        class MaxWeight {
            private List path;
            private int weight;

            public List getPath() {
                return path;
            }

            public void setPath(List path) {
                this.path = path;
            }

            public int getWeight() {
                return weight;
            }

            public void setWeight(int weight) {
                this.weight = weight;
            }

            public MaxWeight(List path, int weight) {
                this.path = path;
                this.weight = weight;
            }

            @Override
            public String toString() {
                return "MaxWeight{" +
                        "path=" + path +
                        ", weight=" + weight +
                        '}';
            }
        }

        /**
         * 计算路径的分支数量
         */
        private int countPathNumber() {
            int[] numberArray = new int[vertexNum];
            for (int i = 0; i < vertexNum; i++) {
                for (int j = 0; j < vertexNum; j++) {
                    if (matrix[j][i] > 0) {
                        numberArray[j]++;
                    }
                }
            }
            int number = 1;
            for (int k = 0; k < vertexNum; k++) {
                if (numberArray[k] > 1) {
                    number++;
                }
            }
            return number;
        }

        /**
         * 判断当前路径是否被已有路径的结果集合所包含
         */
        private boolean containBranch(List> nodeLists, List edges) {
            for (List list : nodeLists) {
                if (list.containsAll(edges)) {
                    return true;
                }
            }
            return false;
        }
    }
}
}

 

字符串全排列

public class 字符串全排列 {
    public static void main(String[] args) {
        String str = "abc";
        allArrange(str.toCharArray(), 0);

    }

    public static void allArrange(char[] chars, int n) {
        if (n == chars.length - 1) {
            System.out.println(String.valueOf(chars));
        }
        for (int i = n; i < chars.length; i++) {
            char tmp = chars[i];
            chars[i] = chars[n];
            chars[n] = tmp;
            allArrange(chars, n + 1);
        }
    }
}

 

 

字符串转数字

public class 字符串转数字 {
    public static void main(String[] args) {
        String str = "123";
        System.out.print(strToInt(str));
    }

    public static int strToInt(String str) {
        int result = 0;
        // 空字符串返回0
        if (str.length() == 0) {
            return result;
        }
        char[] chars = str.toCharArray();
        char base = '0';
        for (int i = chars.length; i > 0; i--) {
            result += (chars[chars.length - i] - base) * Math.pow(10, i - 1);
        }
        return result;
    }
}

 

 

day1:请找出数组中的某个数,它的左侧数字相加之和等于右边之和

PS 自己写了20多分钟,无百度 无粘贴。面试要求10分钟写完,可能么?需要说明的是,要判断数组长度为奇数 偶数,懒 只判断了偶数情况,奇数情况类似。

每天一道算法题leetcode_第1张图片

 

public class findSumIndex {

    /**
     * 逐一遍历
     * @param array
     * @return
     */
    public static int findIndexSB(int array[]) {

        for (int i = 1; i < array.length; i++) {
            int totalLeft = 0;
            for (int le = 0; le < i; le++) {
                totalLeft += array[le];
            }
            int totalRight = 0;
            for (int ri = i + 1; ri < array.length; ri++) {
                totalRight += array[ri];
            }
            if (totalLeft == totalRight) {
                return i;
            }
        }
        return -1;

    }

    /**
     * 二分查找
     * @param array
     * @return
     */
    
    // 既然某个数字的左边的值等于右边,那么可以算出数组的全部数值,然后加入一个二分查找的办法,
    // 定位到中间,如果左边的值*2=数组的和-当前位置的值,那么就可以说找到了,如果大于,那就向前移动,小于就向后移动

    public static int findIndex2(int array[]) {

        // 判断数组不为空 数组长度不为0
        if (array == null || array.length == 0) {
            return -1;
        }

        int length = array.length;
        int left = 0;
        int right = length - 1;
        int middle = 0;
        if (length % 2 == 0) {
            middle = length / 2;
        } else if (length % 2 != 0) {
            middle = length / 2 + 1;
        }

        int total = 0;

        // 计算数组总和
        for (int i : array) {
            total += i;
        }

        do {
            // 判断中间index左边的和
            int totalLeft = 0;
            for (int le = 0; le < middle; le++) {
                totalLeft += le;
            }

            // 数组总和减去中间元素 应该等于左右之和
            int doubleV = (total - array[middle]);

            // 左边之和*2小于总和 说明被查找的元素在middle右侧
            // 1 1 1 1 1 3 2 1 2 如3是要找到位置
            if (totalLeft * 2 < doubleV) {
                // 要找的元素往后移动 中间index赋值给左侧index 从middle到右侧作为新的二分查找数组长度。中间到右侧再取一半
                left = middle;
                middle = middle + (length - middle) / 2;

                // 左边之和*2大于总和 说明被查找的元素在middle左侧
            } else if (totalLeft * 2 > doubleV) {
                right = middle;
                middle = left + (middle - left) / 2;
            } else {
                return middle;
            }
        } while (middle > left && middle < right);
        {
            return -1;
        }


    }
    

    public static void main(String[] args) {

        int[] arr = {1, 1, 1, 3, 2, 1};
//        int[] arr = {1, 2, 3, 2, 1};
        findIndex2(arr);
        findIndexSB(arr);
        System.out.println(findIndex2(arr));
        System.out.println(findIndexSB(arr));
    }


}


 

day2:两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
 
示例:
给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

每天一道算法题leetcode_第2张图片

import java.util.Arrays;
import java.util.HashMap;

/**
 * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标
 * 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍
 *  
 * 示例:
 * 给定 nums = [2, 7, 11, 15], target = 9
 * 

* 因为 nums[0] + nums[1] = 2 + 7 = 9 * 所以返回 [0, 1] */ public class twoNum { public static int[] findIndex(int[] nums, int target) { // map遍历 // 时间复杂度可能会是log(n),所以整体复杂度应该略大于O(n) HashMap hm = new HashMap<>(); for (int i = 0; i < nums.length; i++) { int a = nums[i]; int b = target - a; hm.put(a, i); if (hm.containsKey(b)) { return new int[]{hm.get(b), i}; } } return null; } public static void main(String[] args) { int[] arr = {2, 7, 11, 15}; int target = 9; int[] toFind = findIndex(arr, target); // 打印int数组 System.out.println(Arrays.toString(toFind)); } }

 



 

day3:最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:

输入: "cbbd"
输出: "bb"

 

 

 

待续。。。

 

你可能感兴趣的:(Java)