分类 工作总结 下的文章

youtube上看了一个视频,讲聊天的。

聊天确实是有技巧的,幽默风趣也挺重要的。

有趣的事情,有意思的事情。

链表反转-基础篇
题目
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
考察要点

  • 链表的熟悉程度
  • 迭代法和递归法两种实现思路
  • 迭代法:

    • 优点:效率高,运行时间只随循环的增加而增加;无额外开销;
    • 缺点:代码难理解;代码不如递归代码简洁;
  • 递归法:

    • 优点:用有限的循环语句实现无限集合;代码易读;大问题转化成小问题,减少代码量;
    • 缺点:递归不断调用函数,浪费空间;容易造成堆栈溢出。
  • 复杂度:时间复杂度O(N),空间复杂度O(1)

解法1:迭代法
通过双指针,遍历 head 指针,通过中间变量,逐步指向新的 head 节点,完成链表反转

type ListNode struct {
   Val  int
   Next *ListNode
}

func reverseList(head *ListNode) *ListNode {
   if head == nil {
      return nil
   }
   var newHead *ListNode
   for head != nil {
      node := head.Next
      head.Next = newHead
      newHead = head
      head = node
   }
   return newHead
}

解法2:递归法
整体思路是递归到最后一个节点,这个节点就是链表反转后的头节点,这里记作 ret,最终只需要返回这个 ret 指针即可,剩余的都是对中间数据进行指针反转。

type ListNode struct {
   Val  int
   Next *ListNode
}

func reverseList(head *ListNode) *ListNode {
   if head == nil || head.Next == nil {
      return head
   }

   ret := reverseList(head.Next)
   head.Next.Next = head
   head.Next = nil
   return ret
}

链表反转-进阶篇
题目
反转从位置 m 到 n 的链表. 请使用一趟扫描完成反转.
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
考察要点

  • m和n之间的反转与基础篇一样
  • 在m的边界处理,m-1的next指向n;m的next指向n+1
  • 在n的边界处理,n的next指向n-1;
    解法1:迭代法

    func reverseBetween(head *ListNode, m int, n int) *ListNode {
      dummy := ListNode{Val: 0}
      dummy.Next = head
      node := &dummy
      for i := 1; i < m; i++ {
          node = node.Next
      }
      pre := node
      curr := node.Next
      tail := curr
      for i := m; i <= n; i++ {
          nxt := curr.Next
          curr.Next = pre
          pre = curr
          curr = nxt
      }
      tail.Next = curr
      node.Next = pre
      return dummy.Next 
    }

    解法2:递归法

    type ListNode struct {
     Val  int
     Next *ListNode
    }
    
    func rev(root *ListNode) *ListNode {
     if root == nil || root.Next == nil {
        return root
     }
    
     last := rev(root.Next)
     root.Next.Next = root
     root.Next = nil
    
     return last
    }
    func reverseBetween(head *ListNode, left int, right int) *ListNode {
     d := &ListNode{
        Val:  0,
        Next: head,
     }
     h := d
     tmp := head
    
     var leftNode *ListNode
     var rightNode *ListNode
     var prevNode *ListNode
     var nextNode *ListNode
     foundLeft := false
     foundRight := false
     count := 1
     _ = rightNode
     for tmp != nil {
        if foundLeft && foundRight {
           break
        }
    
        if count == left {
           leftNode = d.Next
           d.Next = nil
           prevNode = d
           foundLeft = true
        }
    
        if count == right {
           rightNode = tmp
           nextNode = tmp.Next
           tmp.Next = nil
           foundRight = true
        }
    
        count++
        d = tmp
        tmp = tmp.Next
     }
    
     last := rev(leftNode)
     prevNode.Next = last
     leftNode.Next = nextNode
     return h.Next
    }

敢于面对挑战

敢于推动事情的发展

敢于做计划

敢于协调资源

这都源于今天推动测试网上线的这一件小事的所作所为。

加油,朱建国!95号,加满!

测试分红模块的升级功能,总觉着不会有什么太大问题,所以比较随意和放松

昨天跑一个升级case时候,发现了严重的分叉BUG。

晚上八点联系同事,分析原因,定位问题。感谢晓亮同学和吕聪同学支持,一个多小时的讨论基本已经分析定位完毕。

写分析报告文档和解决方案

第二天早上晨会前把文档发了出去,领导拍板定了方案,现在开始修改和自测。

总结:
前紧后松,要抓紧时间推进度,这是个老生常谈的问题了,对于我来说,很多事总有拖延症,不到最后不想彻底解决。结果拖到最后出现一堆问题。以后要赶在时间的一半处就要解决完,留给后面充足的时间来解决应急问题。

出现问题,不要怕,慢慢分析,找人协调,请求帮助。

今天调试okc的分红脚本,新引入了测试用例,测试升级过程中,不同版本升级过程,需要持续交易。

然后代码写完了,一测试起来,发现还是自己有很多坑没有遇到过。

研发就是这样,不论你技术再牛,遇到一个新的技术,该走的坑,一个都不会少。

那经验丰富能说明什么呢?

只是证明,你解决问题能力很强,遇到过类似的问题,踩过类似的坑;理解问题更快,解决问题更快;查询资料能力更强。

但是,遇到新的技术,该走的坑一个都少不了,别人趟过的雷,需要继续趟。

所以只能心平气和,面对这些坑,该走的路仍然要走。

技术,1就是1,0就是0,不懂就是不懂,不会就是不会,错了就是错了。

耐心对于程序员来说,是个很好的美德