IT SHARE https://blogtao.com Thu, 02 Nov 2023 07:32:43 +0000 zh-CN hourly 1 https://wordpress.org/?v=6.3.2 https://blogtao.com/wp-content/uploads/2023/02/cropped-2-32x32.png IT SHARE https://blogtao.com 32 32 Java的LinkedList中获取元素并比较的注意事项 https://blogtao.com/archives/568 Thu, 02 Nov 2023 07:32:43 +0000 https://blogtao.com/?p=568 Read More Read More

]]>
我在写LCR 184. 设计自助结算系统这一题遇到问题,我的代码逻辑和官方题解是一样的,但是有部分测试用例无法通过,经过力扣评论区的评论提醒,发现原因是LinkedList返回的值是泛型E,如果数字范围不在[-128, 127]就会新建一个对象,两个数字的Integer对象在比较的时候比较的是地址,应该用.equals()方法比较Integer的内容是否相同。

]]>
小总结 https://blogtao.com/archives/565 https://blogtao.com/archives/565#respond Tue, 24 Oct 2023 14:25:03 +0000 https://blogtao.com/?p=565 Read More Read More

]]>
我总计了我学习动力不足的原因:

(1)对目标不够明确,不知道自己最想达到的目标是什么。因为缺乏明确的目标的激励,导致动力不足。

(2)锻炼身体的频率还不够,每天适量的运动可以保持很好的斗志,运动也能够让人更专注,专注力这对我这种需要高强度用脑的人至关重要。

(3)睡眠不足,睡眠不足会导致容易犯困,困倦就会低效率学习,低效率学习导致内心纠结,进一步导致低效率。

]]>
https://blogtao.com/archives/565/feed 0
try-catch-finally中return语句返回值问题 https://blogtao.com/archives/558 https://blogtao.com/archives/558#respond Wed, 11 Oct 2023 06:52:07 +0000 https://blogtao.com/?p=558

]]>
https://blogtao.com/archives/558/feed 0
ARTS打卡第五周 https://blogtao.com/archives/534 https://blogtao.com/archives/534#respond Fri, 22 Sep 2023 02:52:01 +0000 https://blogtao.com/?p=534 Read More Read More

]]>
Algorithm:

33. 搜索旋转排序数组

这道题充分考察二分法的理解和应用,二分法最难的是在什么情况用等号,什么情况不用等号。我也是看题解弄明白的。
class Solution {
    public int search(int[] nums, int target) {
        int left=0, right=nums.length-1, mid;
        while(left<=right){
            mid=left+(right-left)/2;
            if(nums[mid]==target){
                return mid;
            }
            if(nums[mid]>=nums[left]){
                if(target>=nums[left] && target<nums[mid]){
                    right=mid-1;
                } else {
                    left=mid+1;
                } 
            } else {
                if(target>nums[mid] && target<=nums[right]){
                    left=mid+1;
                } else {
                    right=mid-1;
                }
            }
        }
        return -1;
    }
}

 

当nums[mid]>=nums[left],说明mid在左边的有序区间,这时可以在左边的区间使用二分查找,否则就在右边的有序区间使用二分查找,注意nums[mid]==nums[left]时,仍然要在左边的区间寻找target。

当在左边查找target时,target>=nums[left] && target<nums[mid]时,right=mid-1,否则就让right=mid+1,为什么要有等号呢,因为 [left, mid) 范围是有序的,我们仍然要在左边查找,不能跑到mid的右边。

当在右边查找target时,target>nums[mid] && target<=nums[right]时,left=mid+1,否则就让right=mid-1,这里为什么有等号呢,因为 (mid, right] 范围是有序的,不能跑到左边。

Review:

 

Tip:

1、今天学习《深入理解Java虚拟机》,自己动手编译一个JDK,书中的例子是JDK12,所以需要gcc-7和g++-7,并且把gcc和g++的优先级设为gcc-7和g++-7,所有命令使用sudo运行,这样就不会报错。

2、Java 中的内部类有两类,根据oracle的文档,有两种内部类,非静态的和静态的,非静态的嵌套类叫做内部类,静态的嵌套类叫做静态嵌套类。

3、使用MySQL的load指令批量插入数据,需要注意文件的路径不能有中文,而且Windows环境下要对文件夹的’/’分隔符做’//’转义,或者直接用’/’,插入的目标表也要写上具体的数据库,比如tb_sku数据库下面的tb_sku表,写成tb_sku.tb_sku的形式。

以下两种示例

load data local infile 'D:q/tb_sku5.sql' into table tb_sku.tb_sku fields terminated by ',' lines terminated by '\n';
load data local infile 'D:q\\tb_sku5.sql' into table tb_sku.tb_sku fields terminated by ',' lines terminated by '\n';

4、Java 的线程可以使用join()方法等待这个线程终止。

5、使用快指针每次走两个位置,慢指针每次走一个位置,可以判断一个链表的个数是否为奇数,如果链表元素个数为奇数,fast指针指向最后一元素,slow指针指向中间的元素。如果链表元素个数为偶数,fast指针指向倒数第二个元素,slow指针指向前一半元素的最后一个元素。

Share:

学习完堆排序,做个分享。我写的是大顶堆,堆排序的三个步骤是:

(1)从堆的最后一个建立一个非叶子节点建立堆

(2)把堆顶元素放到最后面的位置

(3)从堆顶继续建立堆

注意(2)和(3)步要循环做下去,直到遇到移动完所有的元素。

步骤(1)是初始整个数组元素成一个堆结构,然后在循环体里面执行(2)和(3),步骤(1)从索引位置arr.length/2-1位置开始建立堆,直到索引是0。经过步骤(1),堆的顶部元素是最大值,所以循环体里面要先把0索引处元素和最后一个元素交换,然后对索引[0, cnt]范围的元素从0位置建立堆,因为0索引的元素被更换过,并且这时候堆的大小减少1,这个减少的操作用cnt控制。

我写了一个测试程序,经过测试,我的代码没有问题。

 

import java.util.Arrays;
import java.util.Random;

public class HeapSort {
    public static void main(String[] args) {
        int len = 200;
        int[] arr = new int[len];
        Random random = new Random();
        boolean flag = true;
        int num = 100;
        while (num-- >= 0) {

            for (int i = 0; i < arr.length; i++) {
                arr[i] = random.nextInt(len);
            }
            int[] copyArr = Arrays.copyOf(arr, arr.length);
            Arrays.sort(copyArr);

            for (int i = arr.length / 2 - 1; i >= 0; i--) {
                heapify(arr, i, arr.length);
            }

            for (int cnt = arr.length - 1; cnt >= 0; cnt--) {
                swap(arr, 0, cnt);
                heapify(arr, 0, cnt);
            }
            
            if (!Arrays.equals(arr, copyArr)) {
                flag = false;
            }
        }
        if (flag) {
            System.out.println("相等");
        } else {
            System.out.println("不相等");
        }
    }

    public static void swap(int[] arr, int a, int b) {
        int tmp = arr[a];
        arr[a] = arr[b];
        arr[b] = tmp;
    }

    public static void heapify(int[] arr, int i, int len) {
        int largest = i;
        int left = 2 * i + 1;
        int right = 2 * i + 2;

        if (left < len && arr[left] > arr[largest]) {
            largest = left;
        }

        if (right < len && arr[right] > arr[largest]) {
            largest = right;
        }

        if (largest != i) {
            swap(arr, i, largest);
            heapify(arr, largest, len);
        }
    }
}

 

]]>
https://blogtao.com/archives/534/feed 0
ARTS打卡第四周 https://blogtao.com/archives/518 https://blogtao.com/archives/518#respond Wed, 13 Sep 2023 02:45:00 +0000 https://blogtao.com/?p=518 Read More Read More

]]>
  • Algorithm主要是为了编程训练和学习。每周至少做一个 leetcode 的算法题(先从Easy开始,然后再Medium,最后才Hard)。进行编程训练,如果不训练你看再多的算法书,你依然不会做算法题,看完书后,你需要训练。关于做Leetcode的的优势,你可以看一下我在coolshell上的文章 Leetcode 编程训练 – 酷 壳 – CoolShell
  • Review:主要是为了学习英文,如果你的英文不行,你基本上无缘技术高手。所以,需要你阅读并点评至少一篇英文技术文章,我个人最喜欢去的地方是Medium.com(需要梯子)以及各个公司的技术blog,如Netflix的。
  • Tip:主要是为了总结和归纳你在是常工作中所遇到的知识点。学习至少一个技术技巧。你在工作中遇到的问题,踩过的坑,学习的点滴知识。
  • Share:主要是为了建立你的影响力,能够输出价值观。分享一篇有观点和思考文章。
  • Algorithm:

    剑指 Offer 31. 栈的压入、弹出序列 这个题目考的是模拟,很多笔试题喜欢考察模拟,一方面模拟类型的题目能考察应聘者对于一段文字的抽象能力,另一方面可以考察应聘者熟练使用已有的数据结构。这道题目要求判断一个出栈顺序是否为入栈顺序的一个正确出栈顺序。借助栈的模拟,每次遍历pushed数组,加入一个元素之后,就去遍历popped数组,如果当前栈不为空且遍历的popped[j]和栈顶元素相等就把栈顶元素弹出来,继续遍历popped数组。等遍历popped数组结束之后就继续添加pushed数组的元素到栈顶,当所有的pushed元素遍历完,我们就模拟完入栈和出栈的顺序,这时候如果栈里面还有元素,说明出栈顺序是错的,返回false,栈为空,返回true。

    Review:

    Leadership is a Research Project  

    文章主要讨论领导力是一个研究型的项目,文章观点是认为项目由人组成,很多领导想成为技术专家,但是他们的方向不精确,领导更应该专注于市场和生意,领导要把注意力放在市场,竞争者,策略上面。领导要研究哪些内容呢,主要是员工的经历,目标,工作上的困难,爱好,失眠的原因。总的来说,领导要研究的是员工。

    Tip:

    (1)遇到一个完全背包的问题,这个完全背包的重点是初始化,因为要求的是最小值,所以除了下标为0的元素,其他元素都要初始化为最大值。这个题目的意思是这样的:给定一个数组arr=[1,2,3,5]和目标长度len=9,用arr里面的长度组成目标长度,不限制使用arr里面的元素次数,求使用的最少元素数目。递推公式很容易想到dp[i]=min(dp[i], dp[i-arr[j]]+1),dp数组中除了下标为0的元素初始化为0,其他元素初始化为Integer.MAX_VALUE-1,不能直接初始化为Integer.MAX_VALUE,否则会溢出。

    (2)做题遇到一个对Java的Map中元素排序的问题,要求是对Map中的元素按照value从大到小排序,如果value相同,就按照key从小到大排序。具体的代码如下

    import java.util.*;
    
    class Solution {
        public static void main(String[] args) {
    
            HashMap<String, Integer> map = new HashMap<>();
            map.put("A", 5);
            map.put("B", 5);
            map.put("C", 4);
            map.put("D", 3);
            map.put("E", 6);
            List<Map.Entry<String, Integer>> list = new LinkedList<>(map.entrySet());
            list.sort((o1, o2) -> {
                int res = o2.getValue() - o1.getValue();
                if (res == 0) {
                    res = o1.getKey() .compareTo(o2.getKey());
                }
                return res;
            });
            for(Map.Entry<String,Integer> entry : list){
                System.out.println(entry.getKey()+" "+entry.getValue());
            }
        }
    }

    (3)Java的Queue添加元素有两个方法,add()和offer()的区别如下:

    add(): 如果有空间,则将指定元素插入到队列末尾,成功时返回 true,如果当前没有可用空间,则抛出IllegalStateException此方法返回一个布尔值,表示操作是否成功。如果元素已添加,则返回 true,否则返回 false。

    offer(): 如果可以立即插入指定的元素而不违反容量限制,则它将指定的元素插入此队列。当使用容量受限的队列时,此方法通常优于add(E),后者只能通过抛出异常来插入元素失败。

    (4)刷题时会用到字符的计算,比如 ch=’e’,现在我们要把ch变为大写的字符,可以这样做:ch=(char)(‘A’+ch – ‘a’); 注意(‘A’+ch -‘a’)的结果是整数,要转为范围更小的char类型,使用强制类型转换。

    Share:

    我发现焦虑不能解决问题,事情是这样的,之前因为有些很想去的岗位投递之后简历没通过,或者笔试没通过,我就感到非常焦虑,后来我想通了,我当下的困难是自己的能力还不够,应该继续提升,不能一看到牛客网上的人炫耀offer就乱了自己的节奏,所以还要继续巩固技术和编程能力。

    ]]>
    https://blogtao.com/archives/518/feed 0
    ARTS打卡第三周 https://blogtao.com/archives/506 https://blogtao.com/archives/506#respond Sun, 03 Sep 2023 09:42:13 +0000 https://blogtao.com/?p=506 Read More Read More

    ]]>
    坚持做一件费脑子的事情很费劲。看看坚持三个月会有什么结果吧。

    Algorithm:

    剑指 Offer 26. 树的子结构   这一题结合二叉树的遍历和判断两个二叉树相等 的知识点,如果你不能看出这一点,说明你的基础还不够扎实。但是这一题有一点需要注意的地方:在判断两个树是否相等时,注意较小的那一棵树的左子树或者右子树可能是空的,要对这两个情况做判断。

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public static boolean flag;
        public boolean isSubStructure(TreeNode A, TreeNode B) {
            flag=false;
            traversal(A, B);
            return flag;
        }
    
        public static void traversal(TreeNode root, TreeNode B){
            if(root==null || B==null){
                return;
            }
            if(root.val == B.val){
                if(isSameTree(root, B)){
                    flag=true;
                }
            }
            traversal(root.left, B);
            traversal(root.right, B);
    
        }
        public static boolean isSameTree(TreeNode p, TreeNode q) {
            if(p==null && q==null){
                return true;
            }
            if(p!=null && q!=null){
                if(q.left==null && q.right==null){
                    return p.val==q.val;
                }
                if(q.left==null && q.right!=null){
                    return p.val==q.val && isSameTree(p.right, q.right);
                }
                if(q.left!=null && q.right==null){
                    return p.val==q.val && isSameTree(p.left, q.left);
                }
                return p.val==q.val && isSameTree(p.left, q.left)
                        && isSameTree(p.right, q.right);
            }
            return false;
        }
    }

     

    Review:

    How Spring Boot Annotations Works? Spring Boot中经常用到注解,文章没有解释注解的原理,文章是Spring Boot注解的使用说明书,@RestController有些特别,它混合@Controller和@ResponseBody,这样的特点让controller里面的方法自动被@ResponseBody注解,意味着方法的返回值应该被直接序列化HTTP 响应体。

    Tip:

    在刷题和工作中会遇到把Java的List转为数组的情况,现在介绍3种方法:

    • 遍历List并把元素放进数组。
    • 使用Stream。数组的类型是引用类型。
    import java.util.*;
    
    class test1 {
        public static void main(String[] a) {
            ArrayList<Integer> list = new ArrayList<>();
            Random rand=new Random();
            for(int i=0; i<10; i++){
                list.add(rand.nextInt(20));
            }
            Integer[] arr1;
            arr1=list.stream().toArray(Integer[]::new);
            System.out.println(Arrays.toString(arr1));
        }
    }
    • 使用List的toArray()方法,第一种是往toArray()里面传入数组,但是数组是引用类型;另一种是不向toArray()里面传参数,数组的类型是Object。
    import java.util.*;
    
    class test1 {
        public static void main(String[] a) {
            ArrayList<Integer> list = new ArrayList<>();
            Random rand=new Random();
            for(int i=0; i<10; i++){
                list.add(rand.nextInt(20));
            }
            Integer[] arr1=new Integer[10];
            list.toArray(arr1);
            Object[] arr2;
            arr2= list.toArray();
            System.out.println(Arrays.toString(arr1));
            System.out.println(Arrays.toString(arr2));
        }
    }

    Share:

    我觉得盲目学习和用蛮力学习并延长学习时间是没有价值的。知道哪些知识不用学习比盲目地学习更省力。人的精力有限,一天能高效学习4个小时就很不错,剩下的时间用来处理不需要很大脑力地事情或者户外活动。媒体上经常喜欢流传某某学生“十分刻苦,一整天任务安排的满满当当”,我觉得99%的人做不到,人的注意力在一天之中是限量的,不可能持续高强度学习,当然有些人精力旺盛,可以持续高强度学习,但是我经过实践,发现自己的节奏更适合持续3~4小时集中精力攻克困难问题,剩下的时间就很低效。

    ]]>
    https://blogtao.com/archives/506/feed 0
    模拟任务调度2题总结 https://blogtao.com/archives/501 https://blogtao.com/archives/501#comments Fri, 01 Sep 2023 03:31:55 +0000 https://blogtao.com/?p=501 Read More Read More

    ]]>
    任务模拟调度2题

    Friday, September 1, 2023

    11:03 AM

     

    1. 有2个电梯,每个电梯一次只能载一个人,现在输入一行数字,表示不同的人从一层到达目的层数并且电梯返回到一层所需要的时间,计算送完所有人需要的最短时间。

    测试用例:

    输入:time=[4,1,2,3,1]

    输出:6

    2. 牛牛是一只聪明的牛,它是一个任务调度专家。在一个动物园中,有许多动物需要执行不同的任务。牛牛需要设计一个任务调度系统来管理动物的任务执行顺序。每个动物的任务执行时间不同,并且每个动物只能执行一次任务。牛牛希望通过合理的任务调度,使得完成所有任务的总时间最小。请你编写一个函数animalTaskScheduler,接收一个整数数组taskDurations和一个整数capacity作为参数,表示动物的任务执行时间和可以同时执行任务的容量。函数应返回一个整数,表示完成所有任务的最短时间。

    测试用例:

    输入:[3, 2, 4, 1, 5],3

    输出:8

     

    以上2题都是相同类型的题目,可以使用“模拟+贪心”的方法解决,具体思路是这样:注意这类题一般不能对已有的序列排序。我们使用一个优先队列保存已经处理的任务,我们每次从任务中取出一个未处理的任务加入到队列中,直到队列中元素个数等于capacity,然后在队列中取一个最短时间任务和当前的未处理任务的时间加在一起,得到一个结果放回队列,最终遍历完所有的未处理任务,选取优先队列中最大的一个元素作为结果返回。

    代码如下:

     

    import java.util.*;
    
    
    public class Solution {
        public static void main(String[] args) {
            int[] taskDurations={4,1,2,3,1};
            int capacity=2;
            System.out.println(animalTaskScheduler(taskDurations, capacity));
    
        }
        /**
         * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
         *
         *
         * @param taskDurations int整型一维数组
         * @param capacity int整型
         * @return int整型
         */
        public static int animalTaskScheduler (int[] taskDurations, int capacity) {
            // write code here
            Queue<Integer> queue=new PriorityQueue<>();
            for(int i=0; i<taskDurations.length; i++){
                if(queue.size()<capacity){
                    queue.add(taskDurations[i]);
                } else {
                    int t=queue.poll();
                    t+=taskDurations[i];
                    queue.add(t);
                }
            }
            int res=0;
            while(!queue.isEmpty()){
                res=queue.poll();
            }
            return res;
        }
    }

     

    ]]>
    https://blogtao.com/archives/501/feed 2
    ARTS打卡第二周 https://blogtao.com/archives/489 https://blogtao.com/archives/489#respond Sat, 26 Aug 2023 10:14:39 +0000 https://blogtao.com/?p=489 Read More Read More

    ]]>
    Algorithm:

    剑指 Offer 34. 二叉树中和为某一值的路径 这道题的解法和我之前遇到的回溯法题目有些区别,不能盲目套用模板。这里的数据结构是树,不用for循环遍历当前层次的其他元素,只需要递归下一层的节点。不变的是每一次回溯之后都要把当前节点的值从sum和ans中删掉。并且结束递归的条件不能放在下一层,在当前层判断当前的节点是否为叶子节点,如果为叶子节点就结束递归。 以下是我的解答。

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode() {}
     *     TreeNode(int val) { this.val = val; }
     *     TreeNode(int val, TreeNode left, TreeNode right) {
     *         this.val = val;
     *         this.left = left;
     *         this.right = right;
     *     }
     * }
     */
    class Solution {
        private static List<List<Integer>> list;
        public List<List<Integer>> pathSum(TreeNode root, int target) {
            List<Integer> ans=new ArrayList<>();
            list=new ArrayList<>();
            if(root==null){
                return list;
            }
            int sum=0;
            backtrack(root, ans, sum, target);
            return list;
        }
        private static void backtrack(TreeNode root, List<Integer> ans, int sum, int target){
            
            if(root==null){
                return;
            }
            sum+=root.val;
            ans.add(root.val);
            if(root.left==null && root.right==null){
                if(sum==target){
                    list.add(new ArrayList<>(ans));
                }
            } else {
    
                backtrack(root.left, ans, sum, target);
                backtrack(root.right, ans, sum, target);
            }
            //System.out.println(sum);
      
            sum-=root.val;
            ans.remove(ans.size()-1);
        }
    }

     

    Review:

    Timestone: Netflix’s High-Throughput, Low-Latency Priority Queueing System with Built-in Support for Non-Parallelizable Workloads

    文章有点长,我挑重点说:要使用netflix出品的高吞吐量、低延迟的优先队列,需要满足以下情况:

    1. 任何时候,一个一个消息只能被分配给一个工作者。摄象这样的情境:我们在资源密集型的工作中可以扇出(fan out)成千上万的活动,当同步复制功能有延迟,我们给B工作者展示一个可以出队的消息,但是这个消息在另一个不同的节点上被A工作者出队了,这样的情况导致我们浪费了一次计算循环。我们需要在队列上保证 linearizable consistency。
    2. 允许非并行化的工作。
    3. 允许使用过滤器的出队和入队的深度查询。
    4. 允许在接收时消息自动创建队列。
    5. 在 1 秒内使一个消息为可出队状态。

    Tip:

    我在工作中主要是写接口API,为了测试API,经常调用API接口,前端团队也会调用我写的接口,但是我们目前开发的项目没有专人负责测试,所以测试数据很不规范,导致数据库有很多脏数据,我认为可以在测试之前规范测试数据的格式和删除数据的顺序,然后统一生成测试数据,用这些数据去测试接口。

    Share:

    平台很重要,程序员就应该去大厂见识一下大流量、高并发、以及精巧的设计,并且大厂的开发流程规范,每一个人的职责都清晰,而在小公司,可能就是身兼数职,俗称全干工程师,这种状况不利于工程师的学习和成长,在程序员升压的早期,应该深入一个领域,不能蜻蜓点水,今天搞一下前端,明天去写一下后端。比如要成为Java后端开发工程师,就不应该在前端页面上花时间,而是去把Java虚拟机和相关的框架吃透。我有一段时间在一个小公司做Java开发实习生,连前端页面都要写,我深感不妙,全栈虽然听起来高级,但是学的杂,没有明确的方向。

    ]]>
    https://blogtao.com/archives/489/feed 0
    复制的SQL语句执行报错 https://blogtao.com/archives/485 https://blogtao.com/archives/485#comments Sat, 19 Aug 2023 07:35:39 +0000 https://blogtao.com/?p=485 Read More Read More

    ]]>
    今天从一个教程复制SQL语句放在自己的环境中执行,我的环境是MySQL 5.7.43 版本,Windows 10环境,报错

    [2023-08-19 15:30:44] [22001][1292] Data truncation: Incorrect datetime value: ‘2019‐10‐01 11:42:08’ for column ‘birthday’ at row 2
    [2023-08-19 15:30:44] [22007][1292] Incorrect datetime value: ‘2019‐10‐01 11:42:08’ for column ‘birthday’ at row 2

    经过检查,发现是生日那一列数据的编码有问题,我删除掉那一列,重新手打字输入,问题解决。

    ]]>
    https://blogtao.com/archives/485/feed 2
    ARTS打卡记录第一周 https://blogtao.com/archives/469 https://blogtao.com/archives/469#respond Tue, 15 Aug 2023 15:45:07 +0000 https://blogtao.com/?p=469 Read More Read More

    ]]>
    重温陈皓对于ARTS的定义

    • Algorithm主要是为了编程训练和学习。每周至少做一个 leetcode 的算法题(先从Easy开始,然后再Medium,最后才Hard)。进行编程训练,如果不训练你看再多的算法书,你依然不会做算法题,看完书后,你需要训练。关于做Leetcode的的优势,你可以看一下我在coolshell上的文章 Leetcode 编程训练 – 酷 壳 – CoolShell
    • Review:主要是为了学习英文,如果你的英文不行,你基本上无缘技术高手。所以,需要你阅读并点评至少一篇英文技术文章,我个人最喜欢去的地方是Medium.com(需要梯子)以及各个公司的技术blog,如Netflix的。
    • Tip:主要是为了总结和归纳你在是常工作中所遇到的知识点。学习至少一个技术技巧。你在工作中遇到的问题,踩过的坑,学习的点滴知识。
    • Share:主要是为了建立你的影响力,能够输出价值观。分享一篇有观点和思考文章。

     

    Algorithm:

    199. 二叉树的右视图 – 力扣(LeetCode)

    第二次练习二叉树的右视图,还是忽略了这种情况

    我只考虑了右视图的节点都在右子树上,没有考虑到右视图在左子树上的情况。对与树的处理,常见有两种:深度遍历和广度遍历。这道题当然要采用广度遍历,所以自然用队列这个数据库结构保存节点。

    Review:

    我阅读了medium上一篇介绍 Java 的 static 关键字的文章Understanding the Static Keyword in Java

    这个文章中重点谈到不适合使用static关键字的场景,我之前确实没有关注过,比如过度使用static关键字会破坏封装性。避免在多线程环境中使用static关键字,因为在多线程环境中使用static关键字会导致同步问题和线程安全问题。对于每个实例都要一份拷贝值的可变数据,不能使用static,否则导致不同实例的变量的值被异常修改。过量使用static方法还会导致代码和某个类过于耦合,不利于单元测试和修改的独立性。不过我不明白为什么“过量使用static方法还会导致代码和某个类过于耦合”。

    Tip:

    1. 多个表使用外键关联在一起,这里姑且认为A表的主键是B表的外键,B表的主键是C表的外键,删除A表的某一条数据时,没有把它关联的B表和C表中的数据也删除掉,所以导致这样一个问题:我们想把A,B,C表中的某些数据在他们原来的表中复制一份,但是B表和C表复制后的数据还要和A表复制后的数据建立关联,所以我使用Map来保存A表、B表、C表中原来的主键和复制后的数据的主键之间的映射关系,原来的主键为key,复制后的主键为value,复制的顺序是A表、B表、C表,但是在接口测试中发现B表中有些数据的外键在Map中找不到它关联的新外键。具体表现为插入复制后的B表的数据,会抛出一个空指针异常,原因是B表中某条复制的数据有个字段为null。
    2. 排查过程:先打上断点,通过空指针异常找到某个主键在Map中没有对应的value,查看Map中确实没有对应数据,然后去数据库看,发现这条缺失的数据在A表中被标记为已删除,Map没有保存这条数据,但是它关联的B表的数据没有标记为删除,所以根据B表的外键查找不到这条数据。怀疑是有人直接操作数据库的数据,没有通过接口去删除数据库的元素,只能通过规范开发和测试流程解决问题。

    Share:

    增查改删,即CRUD,这种工作只能提升开发人员对于业务的理解,但是很难提升技术能力,比较有趣的是我遇到一个数据库的数据修改问题,也就是上面的Tip描述的案例,这个案例我用到的Map处理新旧数据的映射关系的技巧是我从一个力扣的题目中学到的,所以刷力扣确实有帮助,但是纯粹的CRUD工作还是不要沉迷其中,应该做一些更有挑战性的工作,保持对技术的敏感。

    ]]>
    https://blogtao.com/archives/469/feed 0