好长时间没有写博客了,之前因为期末考试耽误了一段时间,回家又玩了几天,然后又赶来上海入职,所以就把博客这事给忘了,哈哈,懒惰啊。

一、最长回文字符串

题目:

/*** 给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。* 在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。* <p>* 注意:* 假设字符串的长度不会超过 1010。* <p>* 示例 1:* 输入:* "abccccdd"* 输出:* 7* 解释:* 我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。*/

这道题的意思很简单,给你一些字母,问你最长可以组成多长的回文字符串。那就想一下回文字符串的判定条件呗,就是中心对称,那就是说中间可以有一个不一样的字符,两边的字符出现的次数是偶数的,那就这样计算吧。

大体的思想就是先对每个字符出现的次数进行计数然后对偶数加和,只加一个奇数,其它奇数减一变偶数加和

    public static int method1(String s) {int[] a = new int[256];for (char c : s.toCharArray()) {a[c]++;}int res = 0;boolean flag = true;for (int i = 0; i < 256; i++) {if (a[i] % 2 == 0) {res += a[i];} else {if (flag) {res += a[i];flag = false;} else {res += a[i] - 1;}}}return res;}

二、第三大的数

题目:

/*** 给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。* * 示例 1:* 输入: [3, 2, 1]* 输出: 1* 解释: 第三大的数是 1.* * 示例 2:* 输入: [1, 2]* 输出: 2* 解释: 第三大的数不存在, 所以返回最大的数 2 .* * 示例 3:* 输入: [2, 2, 3, 1]* 输出: 1* * 解释: 注意,要求返回第三大的数,是指第三大且唯一出现的数。* 存在两个值为2的数,它们都排第二。*/

先给出一种不符合要求的解法,先排序在去重前三大的数,如果去重后的数少于三个就返回最大的数,否则返回第三大的数

    public static int method1(int[] nums) {if (nums.length == 1) {return 0;}Arrays.sort(nums);int[] results = new int[3];int num = 0;for (int i = nums.length - 1; i >= 0; i--) {if (num < 3 && nums[i] != results[num - 1 < 0 ? 0 : num - 1]) {results[num++] = nums[i];}}if (num < 3) {return results[0];} else {return results[2];}}

很明显它的复杂度是超过了O(n)的,sort()的复杂度是O(nlgn)

其实这道题也不难想,就是记录前三大的数都是多少,然后遇到新的数就不断传递就好了,再开始要判断一下数组长度,还有就是在传递数字的时候记录一下改变了多少次,以此来判断有没有第三大的数。

    public static int method2(int[] nums) {if (nums.length == 1) {return nums[0];}if (nums.length == 2) {return Math.max(nums[0], nums[1]);}int max1 = Integer.MIN_VALUE;int max2 = Integer.MIN_VALUE;int max3 = Integer.MIN_VALUE;boolean f = true;int flag = 0;for (int i = 0; i < nums.length; i++) {if (nums[i] == Integer.MIN_VALUE && f) {flag++;f = false;}if (nums[i] > max1) {flag++;//原先第二大传递给第三大max3 = max2;//原先最大值传递给第二大max2 = max1;//更新最大值max1 = nums[i];} else if (nums[i] > max2 && nums[i] < max1) {flag++;max3 = max2;max2 = nums[i];} else if (nums[i] > max3 && nums[i] < max2) {flag++;max3 = nums[i];}}return flag >= 3 ? max3 : max1;}

还是相同的思想,我们来简化一下代码,不使用flag来计数判断是否有第三大的数了,而是在最后判断表示第三大的变量是否改变过,这样判断第三大的数是否出现过。

    public static int method3(int[] nums) {long first = Long.MIN_VALUE, second = Long.MIN_VALUE, third = Long.MIN_VALUE;for (long num : nums) {if (num > first) {third = second;second = first;first = num;} else if (num > second && num < first) {third = second;second = num;} else if (num > third && num < second) {third = num;}}return third == Long.MIN_VALUE ? (int) first : (int) third;}

三、路径数量

题目:

/*** 给定一个二叉树,它的每个结点都存放着一个整数值。* 找出路径和等于给定数值的路径总数。* 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。* 二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。** 示例:* root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8**       10*      /  \*     5   -3*    / \    \*   3   2   11*  / \   \* 3  -2   1** 返回 3。和等于 8 的路径有:** 1.  5 -> 3* 2.  5 -> 2 -> 1* 3.  -3 -> 11*/
public class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}

一看这道题就感觉要用递归解,其实很多树的题用递归来解都非常合适,有一个比较简单的思路来解这道题,就是以每一个节点作为根节点向下寻找是否有符合条件的路径,有的话就把路径数加一,可以用目标数值减去每一个节点,如果可以得到零的话就说明这是一条符合条件的路径,因为可能出现负值,所以不必对下于零的情况做处理。

    private static int pathnumber;public int method1(TreeNode root, int sum) {if(root == null) return 0;Sum(root,sum);method1(root.left,sum);method1(root.right,sum);return pathnumber;}public static void Sum(TreeNode root, int sum){if(root == null) return;sum-=root.val;if(sum == 0){pathnumber++;}Sum(root.left,sum);Sum(root.right,sum);}

简化一下代码就是这个样子,把计数也合到递归里面

    public int method2(TreeNode root, int sum) {if (root == null) return 0;return method2(root.left, sum) + method2(root.right, sum) + dfs(root, sum);}public static int dfs(TreeNode node, int sum) {if (node == null) return 0;int count = 0;if (node.val == sum) count = 1;return count + dfs(node.left, sum - node.val) + dfs(node.right, sum - node.val);}

换汤不换药,可以使用Map来记录每个数值出现的次数,如果加和等于目标数值了便计数,比较重要的有两句话,开始的,<0,1>键值对和最后的回溯。

    public static int method3(TreeNode root, int sum) {HashMap<Integer,Integer> map = new HashMap();//<和,次数>map.put(0, 1);return FindSubTree(root,0,sum,map);}public static int FindSubTree(TreeNode root,int sum,int target,Map<Integer,Integer> map) {if(root==null) {return 0;}sum +=root.val;int res = map.getOrDefault(sum-target, 0);map.put(sum, map.getOrDefault(sum, 0)+1);res +=FindSubTree(root.left,sum,target,map);res +=FindSubTree(root.right,sum,target,map);//回溯map.put(sum, map.get(sum)-1);return res;}

四、N叉树的层次遍历

题目:

/*** 给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。** 例如,给定一个 3叉树 :* LevelOrder.java** 返回其层序遍历:** [*      [1],*      [3,2,4],*      [5,6]* ]** 说明:*     树的深度不会超过 1000。*     树的节点总数不会超过 5000。**/
class Node {public int val;public List<Node> children;public Node() {}public Node(int _val,List<Node> _children) {val = _val;children = _children;}
};

其实很简单,和树的层次遍历一样,可以使用两个队列,先把根节点放到一个队列里,然后取出来的时候加入一个list,再把子节点放到另一个队列里,取出来的时候加入一个list里面,这样不断在两个队列里面捣腾,直到两个队列都为空。

    public List<List<Integer>> method1(Node root) {Queue<Node> nodeQueueA=new LinkedBlockingQueue<>();Queue<Node> nodeQueueB=new LinkedBlockingQueue<>();List<List<Integer>> lists=new ArrayList<>();if (root!=null){nodeQueueA.offer(root);}while (!nodeQueueA.isEmpty()||!nodeQueueB.isEmpty()){List<Integer> integers=new ArrayList<>();while (!nodeQueueA.isEmpty()){Node node=nodeQueueA.poll();integers.add(node.val);for (Node node1:node.children){nodeQueueB.offer(node1);}}if (!integers.isEmpty()){lists.add(integers);integers=new ArrayList<>();}while (!nodeQueueB.isEmpty()){Node node=nodeQueueB.poll();integers.add(node.val);for (Node node1:node.children){nodeQueueA.offer(node1);}}if (!integers.isEmpty()) {lists.add(integers);}}return lists;}

也可以使用一个队列,这样你就需要控制每一次取出来多少个了,用以实现分层,每次要把当前队列中节点的所有子节点放入一个list,并把所有子节点放入队列。

    public List<List<Integer>> method2(Node root) {Queue<Node> nodeQueue=new LinkedBlockingQueue<>();List<List<Integer>> lists=new ArrayList<>();if (root!=null){nodeQueue.offer(root);List<Integer> integers=new ArrayList<>();integers.add(root.val);lists.add(integers);}while (!nodeQueue.isEmpty()){List<Integer> integers=new ArrayList<>();int size=nodeQueue.size();for (int i=0;i<size;i++){Node node=nodeQueue.poll();for (Node node1:node.children){nodeQueue.offer(node1);integers.add(node1.val);}}if (!integers.isEmpty()){lists.add(integers);}}return lists;}

简化版本

    public List<List<Integer>> method3(Node root) {List<List<Integer>> result = new LinkedList<>();if (root == null) {return result;}Node head = root;Queue<Node> queue = new LinkedList<>();queue.add(head);while (!queue.isEmpty()) {int size = queue.size();List<Node> nextLayer = new ArrayList<>();List<Integer> layer = new ArrayList<>();for (int i = 0; i < size; i++) {Node node = queue.poll();nextLayer.addAll(node.children);layer.add(node.val);}result.add(layer);queue.addAll(nextLayer);}return result;}

还有一种办法就是用dfs,递归的时候带上层数,这样就知道加到哪个list里面了

    private static List<List<Integer>> list = new ArrayList<>();public static List<List<Integer>> method4(Node root) {dfs(root, 0);return list;}private static void dfs(Node root, int level){if(root == null){return;}if(list.size()<level+1){List<Integer> l = new ArrayList<>();list.add(l);}list.get(level).add(root.val);for (Node node : root.children){dfs(node, level+1);}}

五、字母异位词

题目:

/*** 给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。* 字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。* 说明:*     字母异位词指字母相同,但排列不同的字符串。*     不考虑答案输出的顺序。** 示例 1:* 输入:* s: "cbaebabacd" p: "abc"* 输出:* [0, 6]* 解释:* 起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。* 起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。**  示例 2:* 输入:* s: "abab" p: "ab"* 输出:* [0, 1, 2]* 解释:* 起始索引等于 0 的子串是 "ab", 它是 "ab" 的字母异位词。* 起始索引等于 1 的子串是 "ba", 它是 "ab" 的字母异位词。* 起始索引等于 2 的子串是 "ab", 它是 "ab" 的字母异位词。*/

字母异位词很好判断,只要里面所包含的字母出现的次数一致就叫字母异位词,一个很明显的思路就是存储s子串的字母构成,如果和p一样就记录其实索引,往后不断抛弃s子串尾的字母,加入新的字母进行比对。

    public static List<Integer> method2(String s, String p) {List<Integer> result = new ArrayList<>();int[] p_letter = new int[26];for (int i = 0; i < p.length(); i++) {//记录p里面的数字分别有几个p_letter[p.charAt(i) - 'a']++;}int start = 0; int end = 0;int[] between_letter = new int[26];//记录两个指针之间的数字都有几个while (end < s.length()) {int c = s.charAt(end++) - 'a';//每一次拿到end指针对应的字母between_letter[c]++;//让这个字母的数量+1 如果这个字母的数量比p里面多了,说明这个start坐标需要排除while (between_letter[c] > p_letter[c]) {between_letter[s.charAt(start++) - 'a']--;}if (end - start == p.length()) {result.add(start);}}return result;}
    public static List<Integer> method3(String s, String p) {List<Integer> list = new ArrayList<>();int[] record = new int[128];for(char c: p.toCharArray()){record[c]++;}char[] arr = s.toCharArray();int l=0, r=0;while(r<s.length()){if(record[arr[r]]>0){record[arr[r]]--;r++;if((r-l) == p.length()){list.add(l);}}else{record[arr[l]]++;l++;}}return list;}

【精选】JAVA算法题(二十五)相关推荐

  1. JAVA常见算法题(二十五)

    /*** Java实现中文数字转换为阿拉伯数字* * * @author WQ**/ public class Demo26 {public static void main(String[] arg ...

  2. 【精选】JAVA算法题(十九)

    一.重复的数 题目: /*** 给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,* 使得 nums [i] = nums [j],并且 i 和 j 的差的绝对值最大为 k ...

  3. 【精选】JAVA算法题(十八)

    一.移除链表中指定的节点 题目: /*** 删除链表中等于给定值 val 的所有节点.** 示例:* 输入: 1->2->6->3->4->5->6, val = ...

  4. 【精选】JAVA算法题(十六)

    1.脏矩形合并 题目: 在2D渲染系统中,局部渲染是常见提升渲染性能的方法.如果界面中有元素发生了改变,我们可以将这个元素所占矩形区域标记为脏矩形,那么在接下来的渲染中,我们仅对每个脏矩形所占矩形区域 ...

  5. JAVA入门算法题(十五)

    一.满二叉搜索树 /*** 给定一个二叉树的层序遍历判断是不是一颗满二叉搜索树*/ 大致分为这么几步: 1.处理输入 2.根据满二叉树的节点数量进行排除 3.构建树 4.递归判断 public sta ...

  6. Java学习笔记二十五:Java面向对象的三大特性之多态

    Java面向对象的三大特性之多态 一:什么是多态: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作. 多态性是对象多种表现形式的体现. 现实中,比 ...

  7. 机器学习算法(二十五):KD树详解及KD树最近邻算法

    目录 1 KD树 1.1 什么是KD树 1.2 KD树的构建 1.3 KD树的插入 1.4 KD树的删除 1.5 KD树的最近邻搜索算法 1.5.1 举例:查询点(2.1,3.1) 1.5.2 举例: ...

  8. java面试(二十五)--(1)redis为什么读写速率快性能好(2)说说web.xml文件中可以配置哪些内容(3)和的区别(4)扑克牌顺子

    1. redis为什么读写速率快性能好? 1.Redis将数据存储在内存上,避免了频繁的IO操作 2.Redis其本身采用字典的数据结构,时间复杂度为O(1),且其采用渐进式的扩容手段 3.Redis ...

  9. Java选择题(二十五)

    1.下列符号中可以在 java 程序里表示单行注释的是( ) 正确答案: C 你的答案: C (正确) A.– B./* --/ C.// D./** --/ 解释: 1.单行(single-line ...

  10. Java多线程学习二十五:阻塞和非阻塞队列的并发安全原理||如何选择适合自己的阻塞队列?

    阻塞和非阻塞队列的并发安全原理. 之前我们探究了常见的阻塞队列的特点,以 ArrayBlockingQueue 为例, 首先分析 BlockingQueue 即阻塞队列的线程安全原理,然后再看看它的兄 ...

最新文章

  1. Spring踩坑记录
  2. 职场社交是一个真实需求吗?
  3. 【译】 Google: Still in The Search 搜索巨人Google的伟大转变 (二)
  4. Road Construction
  5. java的格式化时间工具类
  6. java thread setname_Java Thread setName()方法
  7. 反直觉的三门问题,为什么80%的人都错了?
  8. Java I/O NIO学习
  9. 移动应用的一般测试流程和需要注意的测试项
  10. mysql tomcat 地址池_MySQL tomcat 数据库连接池配置与使用
  11. 24.1 新建集成库工程
  12. 《涂抹Oracle—三思笔记之一步一步学Oracle》看书笔记(序言)
  13. mysql中哪一个储存逻辑型_《VisualFoxPro》2018秋华东年季学期在线作业(一)二三...
  14. matplotlib画图去掉边缘空白
  15. 一个优秀的平面设计作品需要满足那些特点
  16. 【机器学习必备知识】NumPy线性代数详解
  17. @张小龙 微信开机界面该升级啦!NASA帮你P了9张行星图
  18. KVM虚拟化部署Centos
  19. vue.js鼠标移入变换样式,鼠标移出去除样式(active)实现方法
  20. Web自动化测试(二)

热门文章

  1. 公司信息系统架构建设规划
  2. Uniapp实现证件照提示框模板(小程序+APP)
  3. 【汇智学堂】-JS菜鸟版过河小游戏(之四---全部角色左侧上船与左侧下船)
  4. 源代码,基于Stm32f030单片机开发日历显示,内部包括,按键检测、蓝牙通讯、温度传感器读取以及贪吃蛇游戏
  5. java 程序猿必备技能——Debug详解
  6. 百度副总裁李硕:AI能深入场景创造真价值,从传感器到大屏仅是数字化开始...
  7. (exynos4412)Tiny4412裸机开发-点亮LED灯
  8. 饥荒 服务器没有响应,饥荒:联机版
  9. Hybrid接口的工作原理及其配置
  10. 阿里云 ECS 云计算训练营 Day5:在线编程挑战