Golang每日一练(leetDay0050)-LMLPHP

目录

147. 对链表进行插入排序 Insertion Sort List  🌟🌟

148. 排序链表 Sort List  🌟🌟

149. 直线上最多的点数 Max Points On A Line  🌟🌟🌟

150. 逆波兰表达式求值 Evaluate Reverse Polish Notation  🌟🌟

🌟 每日一练刷题专栏 🌟

Golang每日一练 专栏

Python每日一练 专栏

C/C++每日一练 专栏

Java每日一练 专栏


147. 对链表进行插入排序 Insertion Sort List

给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。

插入排序 算法的步骤:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。每次迭代时,从输入数据中删除一个元素(红色),并就地插入已排序的列表中。

对链表进行插入排序。

示例 1:

Golang每日一练(leetDay0050)-LMLPHP

输入: head = [4,2,1,3]
输出: [1,2,3,4]

示例 2:

Golang每日一练(leetDay0050)-LMLPHP

输入: head = [-1,5,3,4,0]
输出: [-1,0,3,4,5]

提示:

  • 列表中的节点数在 [1, 5000]范围内
  • -5000 <= Node.val <= 5000

代码: 插入排序

package main

import "fmt"

type ListNode struct {
	Val  int
	Next *ListNode
}

func build(list []int) *ListNode {
	head := &ListNode{Val: -1 << 31} //-5000 <= Node.val <= 5000
	for i := len(list) - 1; i >= 0; i-- {
		p := &ListNode{Val: list[i]}
		p.Next = head.Next
		head.Next = p
	}
	return head
}

func (head *ListNode) travel() {
	for p := head.Next; p != nil; p = p.Next {
		fmt.Print(p.Val)
		if p.Next != nil {
			fmt.Print("->")
		}
	}
	fmt.Println("<nil>")
}

func insertionSortList(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	dummy := &ListNode{}
	dummy.Next = head
	cur := head.Next
	lastSorted := head
	for cur != nil {
		if cur.Val >= lastSorted.Val {
			lastSorted = lastSorted.Next
		} else {
			prev := dummy
			for prev.Next.Val < cur.Val {
				prev = prev.Next
			}
			lastSorted.Next = cur.Next
			cur.Next = prev.Next
			prev.Next = cur
		}
		cur = lastSorted.Next
	}
	return dummy.Next
}

func main() {
	nums := []int{4, 2, 1, 3}
	head := build(nums)
	head.travel()
	head = insertionSortList(head)
	head.travel()
	nums2 := []int{-1, 5, 3, 4, 0}
	head2 := build(nums2)
	head2.travel()
	head2 = insertionSortList(head2)
	head2.travel()
}

输出:

4->2->1->3<nil>
1->2->3->4<nil>
-1->5->3->4->0<nil>
-1->0->3->4->5<nil>


148. 排序链表 Sort List

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

示例 1:

Golang每日一练(leetDay0050)-LMLPHP

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:Golang每日一练(leetDay0050)-LMLPHP

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[] 

提示:

  • 链表中节点的数目在范围 [0, 5 * 10^4] 内
  • -10^5 <= Node.val <= 10^5

进阶:你可以在 O(nlogn) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

代码: 归并排序,与147题对比多了对时间和空间复杂度的要求

package main

import "fmt"

type ListNode struct {
	Val  int
	Next *ListNode
}

func build(list []int) *ListNode {
	head := &ListNode{Val: -1 << 31} //-5000 <= Node.val <= 5000
	for i := len(list) - 1; i >= 0; i-- {
		p := &ListNode{Val: list[i]}
		p.Next = head.Next
		head.Next = p
	}
	return head
}

func (head *ListNode) travel() {
	for p := head.Next; p != nil; p = p.Next {
		fmt.Print(p.Val)
		if p.Next != nil {
			fmt.Print("->")
		}
	}
	fmt.Println("<nil>")
}

func sortList(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	slow, fast := head, head.Next
	for fast != nil && fast.Next != nil {
		slow = slow.Next
		fast = fast.Next.Next
	}
	mid := slow.Next
	slow.Next = nil
	left := sortList(head)
	right := sortList(mid)
	return merge(left, right)
}

func merge(a, b *ListNode) *ListNode {
	dummy := &ListNode{}
	cur := dummy
	for a != nil && b != nil {
		if a.Val < b.Val {
			cur.Next = a
			a = a.Next
		} else {
			cur.Next = b
			b = b.Next
		}
		cur = cur.Next
	}
	if a != nil {
		cur.Next = a
	} else {
		cur.Next = b
	}
	return dummy.Next
}

func main() {
	nums := []int{4, 2, 1, 3}
	head := build(nums)
	head.travel()
	head = sortList(head)
	head.travel()
	nums2 := []int{-1, 5, 3, 4, 0}
	head2 := build(nums2)
	head2.travel()
	head2 = sortList(head2)
	head2.travel()
}

输出:

4->2->1->3<nil>
1->2->3->4<nil>
-1->5->3->4->0<nil>
-1->0->3->4->5<nil>


149. 直线上最多的点数 Max Points On A Line

给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。

示例 1:

Golang每日一练(leetDay0050)-LMLPHP

输入:points = [[1,1],[2,2],[3,3]]
输出:3

示例 2:

Golang每日一练(leetDay0050)-LMLPHP

输入:points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出:4

提示:

  • 1 <= points.length <= 300
  • points[i].length == 2
  • -10^4 <= xi, yi <= 10^4
  • points 中的所有点 互不相同

代码1: 暴力枚举

package main

import (
	"fmt"
)

func maxPoints(points [][]int) int {
	if len(points) < 3 {
		return len(points)
	}
	ans := 0
	for i := 0; i < len(points); i++ {
		kMap := make(map[Fraction]int)
		same := 1
		for j := i + 1; j < len(points); j++ {
			dx, dy := points[i][0]-points[j][0], points[i][1]-points[j][1]
			if dx == 0 && dy == 0 {
				same++
				continue
			}
			gcd := GCD(dx, dy)
			f := Fraction{
				Numerator:   dy / gcd,
				Denominator: dx / gcd,
			}
			kMap[f]++
		}
		maxCnt := 0
		for _, cnt := range kMap {
			if cnt > maxCnt {
				maxCnt = cnt
			}
		}
		ans = max(ans, maxCnt+same)
	}
	return ans
}

type Fraction struct {
	Numerator   int
	Denominator int
}

func GCD(a, b int) int {
	if b == 0 {
		return a
	}
	return GCD(b, a%b)
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func main() {
	points := [][]int{{1, 1}, {2, 2}, {3, 3}}
	fmt.Println(maxPoints(points))
	points = [][]int{{1, 1}, {3, 2}, {5, 3}, {4, 1}, {2, 3}, {1, 4}}
	fmt.Println(maxPoints(points))
}

 代码2: 哈希表

package main

import (
	"fmt"
)

func maxPoints(points [][]int) int {
	if len(points) < 2 {
		return len(points)
	}
	ans := 1
	for i, p := range points {
		if ans >= len(points)-i {
			break
		}
		cnt := map[fraction]int{}
		for _, q := range points[i+1:] {
			k := newFraction(p, q)
			cnt[*k]++
		}
		for _, c := range cnt {
			ans = max(ans, c+1)
		}
	}
	return ans
}

type fraction struct {
	dx, dy int
}

func newFraction(p, q []int) *fraction {
	dx, dy := p[1]-q[1], p[0]-q[0]
	if dx == 0 {
		dy = 1
	} else if dy == 0 {
		dx = 1
	} else if dy < 0 {
		dx, dy = -dx, -dy
	}
	g := gcd(abs(dx), abs(dy))
	return &fraction{dx / g, dy / g}
}

func gcd(a, b int) int {
	for b != 0 {
		a, b = b, a%b
	}
	return a
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func main() {
	points := [][]int{{1, 1}, {2, 2}, {3, 3}}
	fmt.Println(maxPoints(points))
	points = [][]int{{1, 1}, {3, 2}, {5, 3}, {4, 1}, {2, 3}, {1, 4}}
	fmt.Println(maxPoints(points))
}

输出:

3
4


150. 逆波兰表达式求值 Evaluate Reverse Polish Notation

根据 逆波兰表示法,求表达式的值。 ​

有效的算符包括 +-*/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

注意 两个整数之间的除法只保留整数部分。

可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3:

输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

提示:

  • 1 <= tokens.length <= 10^4
  • tokens[i] 是一个算符("+""-""*" 或 "/"),或是在范围 [-200, 200] 内的一个整数

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

  • 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
  • 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。

逆波兰表达式主要有以下两个优点:

  • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
  • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

代码1: 栈 stack

package main

import (
	"fmt"
	"strconv"
)

func evalRPN(tokens []string) int {
	stack := make([]int, 0)
	for _, t := range tokens {
		if t == "+" {
			a, b := stack[len(stack)-2], stack[len(stack)-1]
			stack = stack[:len(stack)-2]
			stack = append(stack, a+b)
		} else if t == "-" {
			a, b := stack[len(stack)-2], stack[len(stack)-1]
			stack = stack[:len(stack)-2]
			stack = append(stack, a-b)
		} else if t == "*" {
			a, b := stack[len(stack)-2], stack[len(stack)-1]
			stack = stack[:len(stack)-2]
			stack = append(stack, a*b)
		} else if t == "/" {
			a, b := stack[len(stack)-2], stack[len(stack)-1]
			stack = stack[:len(stack)-2]
			stack = append(stack, a/b)
		} else {
			num, _ := strconv.Atoi(t)
			stack = append(stack, num)
		}
	}
	return stack[0]
}

func main() {
	tokens := []string{"2", "1", "+", "3", "*"}
	fmt.Println(evalRPN(tokens))
	tokens = []string{"4", "13", "5", "/", "+"}
	fmt.Println(evalRPN(tokens))
	tokens = []string{"10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"}
	fmt.Println(evalRPN(tokens))
}

代码2: DFS 递归

package main

import (
	"fmt"
	"strconv"
)

func evalRPN(tokens []string) int {
	var dfs func() int
	dfs = func() int {
		if len(tokens) == 0 {
			return 0
		}
		op := tokens[len(tokens)-1]
		tokens = tokens[:len(tokens)-1]
		if op == "+" {
			return dfs() + dfs()
		} else if op == "-" {
			a, b := dfs(), dfs()
			return b - a
		} else if op == "*" {
			return dfs() * dfs()
		} else if op == "/" {
			a, b := dfs(), dfs()
			return b / a
		} else {
			num, _ := strconv.Atoi(op)
			return num
		}
	}
	return dfs()
}

func main() {
	tokens := []string{"2", "1", "+", "3", "*"}
	fmt.Println(evalRPN(tokens))
	tokens = []string{"4", "13", "5", "/", "+"}
	fmt.Println(evalRPN(tokens))
	tokens = []string{"10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"}
	fmt.Println(evalRPN(tokens))
}

输出:

9
6
22 


🌟 每日一练刷题专栏 🌟

持续,努力奋斗做强刷题搬运工!

👍 点赞,你的认可是我坚持的动力! 

🌟 收藏,你的青睐是我努力的方向! 

评论,你的意见是我进步的财富!  

 主页:https://hannyang.blog.csdn.net/ 

04-30 04:38