【華為機試】34. 在排序數組中查找元素的第一個和最后一個位置

文章目錄

  • 34. 在排序數組中查找元素的第一個和最后一個位置
    • 描述
    • 示例 1:
    • 示例 2:
    • 示例 3:
    • 提示:
    • 解題思路
      • 算法分析
      • 問題本質分析
      • 雙重二分查找詳解
      • 左邊界查找過程
      • 右邊界查找過程
      • 算法流程圖
      • 邊界情況分析
      • 各種解法對比
      • 二分查找變種詳解
      • 時間復雜度分析
      • 空間復雜度分析
      • 關鍵優化點
      • 實際應用場景
      • 二分查找模板
      • 算法擴展
      • 測試用例設計
      • 常見錯誤避免
      • 代碼實現要點
      • 手工驗證示例
    • 完整題解代碼

34. 在排序數組中查找元素的第一個和最后一個位置

描述

給你一個按照非遞減順序排列的整數數組 nums,和一個目標值 target。請你找出給定目標值在數組中的開始位置和結束位置。

如果數組中不存在目標值 target,返回 [-1, -1]。

你必須設計并實現時間復雜度為 O(log n) 的算法解決此問題。

示例 1:

輸入:nums = [5,7,7,8,8,10], target = 8
輸出:[3,4]

示例 2:

輸入:nums = [5,7,7,8,8,10], target = 6
輸出:[-1,-1]

示例 3:

輸入:nums = [], target = 0
輸出:[-1,-1]

提示:

  • 0 <= nums.length <= 105
  • -10^9 <= nums[i] <= 10^9
  • nums 是一個非遞減數組
  • -10^9 <= target <= 10^9

解題思路

算法分析

這道題是二分查找邊界查找的經典應用。主要解法包括:

  1. 雙重二分查找法:分別查找左邊界和右邊界
  2. 單次二分查找法:一次查找確定范圍
  3. 線性查找法:暴力遍歷(不滿足時間復雜度要求)
  4. 庫函數法:使用內置的查找函數

問題本質分析

排序數組范圍查找
二分查找變種
左邊界查找
右邊界查找
范圍確定
找到第一個>=target的位置
找到最后一個<=target的位置
合并兩個邊界結果
時間復雜度O_logn

雙重二分查找詳解

flowchart TDA[輸入nums和target] --> B[查找左邊界]B --> C[left_bound = findLeft]C --> D{左邊界是否存在}D -->|不存在| E[返回[-1,-1]]D -->|存在| F[查找右邊界]F --> G[right_bound = findRight]G --> H[返回[left_bound, right_bound]]B --> I[左邊界二分查找]I --> J[尋找第一個>=target的位置]F --> K[右邊界二分查找]K --> L[尋找最后一個<=target的位置]

左邊界查找過程

flowchart TDA[左邊界查找] --> B[初始化left=0, right=len]B --> C{left < right}C -->|否| D[返回left]C -->|是| E[計算mid = left + (right-left)/2]E --> F{nums[mid] < target}F -->|是| G[left = mid + 1]F -->|否| H[right = mid]G --> CH --> CD --> I[檢查邊界有效性]

右邊界查找過程

flowchart TDA[右邊界查找] --> B[初始化left=0, right=len]B --> C{left < right}C -->|否| D[返回left-1]C -->|是| E[計算mid = left + (right-left)/2]E --> F{nums[mid] <= target}F -->|是| G[left = mid + 1]F -->|否| H[right = mid]G --> CH --> CD --> I[檢查邊界有效性]

算法流程圖

flowchart TDA[開始] --> B[輸入驗證]B --> C{數組為空}C -->|是| D[返回[-1,-1]]C -->|否| E[查找左邊界]E --> F[二分查找第一個>=target]F --> G{找到有效位置}G -->|否| DG -->|是| H{nums[left]==target}H -->|否| DH -->|是| I[查找右邊界]I --> J[二分查找最后一個<=target]J --> K[返回[left, right]]

邊界情況分析

graph TDA[邊界情況] --> B[空數組]A --> C[單元素數組]A --> D[目標不存在]A --> E[全部相同元素]A --> F[目標在首尾]B --> G[直接返回[-1,-1]]C --> H[判斷唯一元素是否匹配]D --> I[兩次二分都找不到]E --> J[返回[0, n-1]]F --> K[邊界處理要準確]

各種解法對比

解法對比
雙重二分查找
單次二分查找
線性查找
庫函數法
時間O_logn空間O_1
時間O_logn空間O_1
時間O_n空間O_1
時間O_logn空間O_1
推薦解法清晰易懂
代碼緊湊但復雜
不滿足題目要求
語言特定實現

二分查找變種詳解

graph TDA[二分查找變種] --> B[查找確切值]A --> C[查找左邊界]A --> D[查找右邊界]A --> E[查找插入位置]B --> F[nums[mid] == target時直接返回]C --> G[nums[mid] >= target時收縮右邊界]D --> H[nums[mid] <= target時收縮左邊界]E --> I[找到第一個>target的位置]F --> J[經典二分查找]G --> K[左邊界二分]H --> L[右邊界二分]I --> M[插入位置二分]

時間復雜度分析

  • 雙重二分查找:O(log n),執行兩次獨立的二分查找
  • 單次二分查找:O(log n),一次遍歷確定范圍
  • 線性查找:O(n),不滿足題目要求
  • 庫函數查找:O(log n),依賴具體實現

空間復雜度分析

  • 雙重二分查找:O(1),只使用常數額外空間
  • 單次二分查找:O(1),只使用常數額外空間
  • 線性查找:O(1),只使用常數額外空間
  • 庫函數查找:O(1),通常只使用常數空間

關鍵優化點

優化策略
邊界處理
提前退出
溢出防護
代碼復用
準確定義開閉區間
空數組直接返回
mid計算防止溢出
統一二分查找模板
避免邊界錯誤

實際應用場景

應用場景
數據庫索引
搜索引擎
數據分析
算法競賽
范圍查詢優化
相關性排序查找
時間序列數據范圍
區間查找問題
核心算法組件

二分查找模板

flowchart TDA[二分查找模板選擇] --> B[左閉右閉 [left, right]]A --> C[左閉右開 [left, right)]A --> D[左開右開 (left, right)]B --> E[right = len - 1]C --> F[right = len]D --> G[left = -1, right = len]E --> H[while left <= right]F --> I[while left < right]G --> IH --> J[經典二分模板]I --> K[邊界查找模板]

算法擴展

算法擴展
查找峰值
旋轉數組查找
二維矩陣查找
第K小元素
山峰數組問題
分治策略
行列有序矩陣
快速選擇算法
二分查找家族

測試用例設計

測試用例
基礎功能
邊界情況
性能測試
目標存在
目標不存在
重復元素
空數組
單元素
全相同
大數組
最壞情況
驗證正確性
驗證性能

常見錯誤避免

常見錯誤
邊界計算錯誤
無限循環
整數溢出
邊界條件遺漏
左右邊界定義不一致
left和right更新錯誤
mid計算溢出
特殊情況未處理
使用統一模板
保證循環收斂
使用安全計算
完善測試用例

代碼實現要點

  1. 二分查找模板

    • 使用左閉右開區間避免邊界錯誤
    • mid計算使用left + (right-left)/2防溢出
    • 明確left和right的更新規則
  2. 邊界查找邏輯

    • 左邊界:找第一個大于等于target的位置
    • 右邊界:找最后一個小于等于target的位置
    • 驗證找到的位置是否有效
  3. 特殊情況處理

    • 空數組直接返回[-1,-1]
    • 目標值不存在返回[-1,-1]
    • 單元素數組的邊界情況
  4. 性能優化技巧

    • 提前判斷邊界情況
    • 使用位運算優化除法
    • 減少重復的邊界檢查

手工驗證示例

數組[5,7,7,8,8,10], target=8
查找左邊界
left=0, right=6
mid=3, nums[3]=8 >= 8, right=3
mid=1, nums[1]=7 < 8, left=2
mid=2, nums[2]=7 < 8, left=3
left=right=3, 左邊界=3
查找右邊界
left=0, right=6
mid=3, nums[3]=8 <= 8, left=4
mid=5, nums[5]=10 > 8, right=5
mid=4, nums[4]=8 <= 8, left=5
left=right=5, 右邊界=4
返回[3,4]

這個問題的關鍵在于理解二分查找的邊界處理掌握左右邊界的查找技巧,通過兩次二分查找分別確定目標值的起始和結束位置。

完整題解代碼

package mainimport ("fmt""sort""strings""time"
)// 解法一:雙重二分查找法(推薦解法)
// 時間復雜度:O(log n),空間復雜度:O(1)
func searchRange(nums []int, target int) []int {if len(nums) == 0 {return []int{-1, -1}}// 查找左邊界leftBound := findLeftBound(nums, target)if leftBound == -1 {return []int{-1, -1}}// 查找右邊界rightBound := findRightBound(nums, target)return []int{leftBound, rightBound}
}// 查找左邊界:第一個大于等于target的位置
func findLeftBound(nums []int, target int) int {left, right := 0, len(nums)for left < right {mid := left + (right-left)/2if nums[mid] < target {left = mid + 1} else {right = mid}}// 檢查找到的位置是否有效if left < len(nums) && nums[left] == target {return left}return -1
}// 查找右邊界:最后一個小于等于target的位置
func findRightBound(nums []int, target int) int {left, right := 0, len(nums)for left < right {mid := left + (right-left)/2if nums[mid] <= target {left = mid + 1} else {right = mid}}// left-1是最后一個小于等于target的位置return left - 1
}// 解法二:優化的雙重二分查找(更清晰的邊界處理)
// 時間復雜度:O(log n),空間復雜度:O(1)
func searchRangeOptimized(nums []int, target int) []int {if len(nums) == 0 {return []int{-1, -1}}// 使用統一的二分查找模板leftBound := binarySearchLeft(nums, target)rightBound := binarySearchRight(nums, target)if leftBound <= rightBound {return []int{leftBound, rightBound}}return []int{-1, -1}
}// 二分查找左邊界(左閉右閉區間)
func binarySearchLeft(nums []int, target int) int {left, right := 0, len(nums)-1for left <= right {mid := left + (right-left)/2if nums[mid] >= target {right = mid - 1} else {left = mid + 1}}// 檢查邊界和目標值if left < len(nums) && nums[left] == target {return left}return len(nums) // 表示未找到
}// 二分查找右邊界(左閉右閉區間)
func binarySearchRight(nums []int, target int) int {left, right := 0, len(nums)-1for left <= right {mid := left + (right-left)/2if nums[mid] <= target {left = mid + 1} else {right = mid - 1}}// 檢查邊界和目標值if right >= 0 && nums[right] == target {return right}return -1 // 表示未找到
}// 解法三:單次二分查找法
// 時間復雜度:O(log n),空間復雜度:O(1)
func searchRangeSingle(nums []int, target int) []int {if len(nums) == 0 {return []int{-1, -1}}// 先用標準二分查找找到任意一個target位置pos := binarySearch(nums, target)if pos == -1 {return []int{-1, -1}}// 從找到的位置向兩邊擴展left, right := pos, pos// 向左擴展找到左邊界for left > 0 && nums[left-1] == target {left--}// 向右擴展找到右邊界for right < len(nums)-1 && nums[right+1] == target {right++}return []int{left, right}
}// 標準二分查找
func binarySearch(nums []int, target int) int {left, right := 0, len(nums)-1for left <= right {mid := left + (right-left)/2if nums[mid] == target {return mid} else if nums[mid] < target {left = mid + 1} else {right = mid - 1}}return -1
}// 解法四:使用Go標準庫
// 時間復雜度:O(log n),空間復雜度:O(1)
func searchRangeStdLib(nums []int, target int) []int {if len(nums) == 0 {return []int{-1, -1}}// 使用sort.SearchInts查找左邊界leftBound := sort.SearchInts(nums, target)// 檢查是否找到目標值if leftBound >= len(nums) || nums[leftBound] != target {return []int{-1, -1}}// 查找右邊界:第一個大于target的位置減1rightBound := sort.SearchInts(nums, target+1) - 1return []int{leftBound, rightBound}
}// 解法五:線性查找法(不滿足時間復雜度要求,僅用于對比)
// 時間復雜度:O(n),空間復雜度:O(1)
func searchRangeLinear(nums []int, target int) []int {left, right := -1, -1// 從左到右找第一個目標值for i := 0; i < len(nums); i++ {if nums[i] == target {left = ibreak}}if left == -1 {return []int{-1, -1}}// 從右到左找最后一個目標值for i := len(nums) - 1; i >= 0; i-- {if nums[i] == target {right = ibreak}}return []int{left, right}
}// 解法六:遞歸二分查找
// 時間復雜度:O(log n),空間復雜度:O(log n)
func searchRangeRecursive(nums []int, target int) []int {if len(nums) == 0 {return []int{-1, -1}}left := findLeftBoundRecursive(nums, target, 0, len(nums)-1)if left == -1 {return []int{-1, -1}}right := findRightBoundRecursive(nums, target, 0, len(nums)-1)return []int{left, right}
}// 遞歸查找左邊界
func findLeftBoundRecursive(nums []int, target, left, right int) int {if left > right {return -1}mid := left + (right-left)/2if nums[mid] == target {// 檢查是否是最左邊的if mid == 0 || nums[mid-1] != target {return mid}return findLeftBoundRecursive(nums, target, left, mid-1)} else if nums[mid] < target {return findLeftBoundRecursive(nums, target, mid+1, right)} else {return findLeftBoundRecursive(nums, target, left, mid-1)}
}// 遞歸查找右邊界
func findRightBoundRecursive(nums []int, target, left, right int) int {if left > right {return -1}mid := left + (right-left)/2if nums[mid] == target {// 檢查是否是最右邊的if mid == len(nums)-1 || nums[mid+1] != target {return mid}return findRightBoundRecursive(nums, target, mid+1, right)} else if nums[mid] < target {return findRightBoundRecursive(nums, target, mid+1, right)} else {return findRightBoundRecursive(nums, target, left, mid-1)}
}// 測試函數
func testSearchRange() {testCases := []struct {nums     []inttarget   intexpected []intdesc     string}{{[]int{5, 7, 7, 8, 8, 10}, 8, []int{3, 4}, "示例1:目標存在多個"},{[]int{5, 7, 7, 8, 8, 10}, 6, []int{-1, -1}, "示例2:目標不存在"},{[]int{}, 0, []int{-1, -1}, "示例3:空數組"},{[]int{1}, 1, []int{0, 0}, "單元素匹配"},{[]int{1}, 2, []int{-1, -1}, "單元素不匹配"},{[]int{1, 1, 1, 1, 1}, 1, []int{0, 4}, "全部相同元素"},{[]int{1, 2, 3, 4, 5}, 1, []int{0, 0}, "目標在首位"},{[]int{1, 2, 3, 4, 5}, 5, []int{4, 4}, "目標在末位"},{[]int{1, 2, 3, 4, 5}, 3, []int{2, 2}, "目標在中間單個"},{[]int{1, 2, 2, 2, 3}, 2, []int{1, 3}, "目標在中間多個"},{[]int{1, 3, 5, 7, 9}, 4, []int{-1, -1}, "目標在間隙"},{[]int{1, 1, 2, 2, 3, 3}, 2, []int{2, 3}, "連續重復"},{[]int{-1, 0, 3, 5, 9, 12}, 9, []int{4, 4}, "包含負數"},{[]int{-3, -1, 0, 3, 5}, -1, []int{1, 1}, "負數目標"},{[]int{0, 0, 0, 1, 1, 1}, 0, []int{0, 2}, "零值連續"},}fmt.Println("=== 查找元素范圍測試 ===\n")for i, tc := range testCases {// 測試主要解法result1 := searchRange(tc.nums, tc.target)result2 := searchRangeOptimized(tc.nums, tc.target)result3 := searchRangeStdLib(tc.nums, tc.target)status := "?"if !equalSlices(result1, tc.expected) {status = "?"}fmt.Printf("測試 %d: %s\n", i+1, tc.desc)fmt.Printf("輸入: nums=%v, target=%d\n", tc.nums, tc.target)fmt.Printf("期望: %v\n", tc.expected)fmt.Printf("雙重二分: %v\n", result1)fmt.Printf("優化二分: %v\n", result2)fmt.Printf("標準庫法: %v\n", result3)fmt.Printf("結果: %s\n", status)fmt.Println(strings.Repeat("-", 40))}
}// 輔助函數:比較兩個切片是否相等
func equalSlices(a, b []int) bool {if len(a) != len(b) {return false}for i := range a {if a[i] != b[i] {return false}}return true
}// 性能測試
func benchmarkSearchRange() {fmt.Println("\n=== 性能測試 ===\n")// 構造測試數據testData := []struct {nums   []inttarget intdesc   string}{{generateSortedArray(1000, 5), 5, "1000元素數組"},{generateSortedArray(10000, 50), 50, "10000元素數組"},{generateSortedArray(100000, 500), 500, "100000元素數組"},{generateRepeatedArray(50000, 42), 42, "50000重復元素"},}algorithms := []struct {name stringfn   func([]int, int) []int}{{"雙重二分", searchRange},{"優化二分", searchRangeOptimized},{"標準庫法", searchRangeStdLib},{"遞歸二分", searchRangeRecursive},{"線性查找", searchRangeLinear},}for _, data := range testData {fmt.Printf("%s:\n", data.desc)for _, algo := range algorithms {start := time.Now()result := algo.fn(data.nums, data.target)duration := time.Since(start)fmt.Printf("  %s: %v, 耗時: %v\n", algo.name, result, duration)}fmt.Println()}
}// 生成有序數組(包含重復元素)
func generateSortedArray(size, targetCount int) []int {nums := make([]int, size)target := size / 2for i := 0; i < size; i++ {if i >= target && i < target+targetCount {nums[i] = target} else if i < target {nums[i] = i} else {nums[i] = i - targetCount + 1}}return nums
}// 生成重復元素數組
func generateRepeatedArray(size, value int) []int {nums := make([]int, size)for i := range nums {if i < size/3 {nums[i] = value - 1} else if i < 2*size/3 {nums[i] = value} else {nums[i] = value + 1}}return nums
}// 演示二分查找過程
func demonstrateBinarySearch() {fmt.Println("\n=== 二分查找過程演示 ===")nums := []int{5, 7, 7, 8, 8, 10}target := 8fmt.Printf("數組: %v, 目標: %d\n", nums, target)fmt.Println("\n查找左邊界過程:")demonstrateLeftBound(nums, target)fmt.Println("\n查找右邊界過程:")demonstrateRightBound(nums, target)result := searchRange(nums, target)fmt.Printf("\n最終結果: %v\n", result)
}func demonstrateLeftBound(nums []int, target int) {left, right := 0, len(nums)step := 1fmt.Printf("初始: left=%d, right=%d\n", left, right)for left < right {mid := left + (right-left)/2fmt.Printf("步驟%d: left=%d, right=%d, mid=%d, nums[%d]=%d\n",step, left, right, mid, mid, nums[mid])if nums[mid] < target {left = mid + 1fmt.Printf("       nums[%d]=%d < %d, left=%d\n", mid, nums[mid], target, left)} else {right = midfmt.Printf("       nums[%d]=%d >= %d, right=%d\n", mid, nums[mid], target, right)}step++}if left < len(nums) && nums[left] == target {fmt.Printf("找到左邊界: %d\n", left)} else {fmt.Println("未找到目標值")}
}func demonstrateRightBound(nums []int, target int) {left, right := 0, len(nums)step := 1fmt.Printf("初始: left=%d, right=%d\n", left, right)for left < right {mid := left + (right-left)/2fmt.Printf("步驟%d: left=%d, right=%d, mid=%d, nums[%d]=%d\n",step, left, right, mid, mid, nums[mid])if nums[mid] <= target {left = mid + 1fmt.Printf("       nums[%d]=%d <= %d, left=%d\n", mid, nums[mid], target, left)} else {right = midfmt.Printf("       nums[%d]=%d > %d, right=%d\n", mid, nums[mid], target, right)}step++}rightBound := left - 1fmt.Printf("找到右邊界: %d\n", rightBound)
}func main() {fmt.Println("34. 在排序數組中查找元素的第一個和最后一個位置")fmt.Println("================================================")// 基礎功能測試testSearchRange()// 性能對比測試benchmarkSearchRange()// 二分查找過程演示demonstrateBinarySearch()// 展示算法特點fmt.Println("\n=== 算法特點分析 ===")fmt.Println("1. 雙重二分:經典解法,兩次獨立二分查找,清晰易懂")fmt.Println("2. 優化二分:統一模板,邊界處理更加清晰")fmt.Println("3. 標準庫法:利用內置函數,代碼簡潔")fmt.Println("4. 遞歸二分:遞歸實現,代碼簡潔但有棧溢出風險")fmt.Println("5. 線性查找:時間復雜度O(n),不滿足題目要求")fmt.Println("\n=== 關鍵技巧總結 ===")fmt.Println("? 左邊界查找:找第一個>=target的位置")fmt.Println("? 右邊界查找:找最后一個<=target的位置")fmt.Println("? 邊界檢查:確保找到的位置值等于target")fmt.Println("? 溢出防護:mid計算使用left+(right-left)/2")fmt.Println("? 模板統一:使用一致的二分查找邊界處理")
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91589.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91589.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91589.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【網絡編程】WebSocket 實現簡易Web多人聊天室

一、實現思路 Web端就是使用html JavaScript來實現頁面&#xff0c;通過WebSocket長連接和服務器保持通訊&#xff0c;協議的payload使用JSON格式封裝 服務端使用C配合第三方庫WebSocket和nlonlohmann庫來實現 二、Web端 2.1 界面顯示 首先&#xff0c;使用html來設計一個…

AI 驅動、設施擴展、驗證器強化、上線 EVM 測試網,Injective 近期動態全更新!

作為一個專注于金融應用、且具有高度可互操作性的高性能 Layer-1 區塊鏈&#xff0c;Injective 自誕生以來便為開發者提供有即插即用的技術模塊&#xff0c;以便開發者能夠更好地搭建新一代 Web3 金融類應用。談及項目發展的愿景和基本定位&#xff0c;創始團隊曾提到希望 Inje…

Qt-----初識

1. 什么是Qt定義&#xff1a;Qt是一個跨平臺的應用程序和用戶界面框架&#xff0c;主要用于開發具有圖形用戶界面的應用程序&#xff0c;同時也支持非GUI程序的開發。 編程語言&#xff1a;主要使用C&#xff0c;但也提供了對Python&#xff08;PyQt&#xff09;、JavaScript&a…

理解微信體系中的 AppID、OpenID 和 UnionID

前言: 在開發微信相關的服務(如小程序,公眾號,微信開放平臺等)時,很多人都會接觸到幾個看起來相似但實際用途不同的額ID: AppiD, OpenID,UnionID. 搞清楚這三者的區別,是微信生態開發中的基本功,本文將從開發者視角觸發,深入淺出地解釋它們的關系,區別以及實際應用場景一.什么是…

FFmpeg,如何插入SEI自定義數據

FFmpeg&#xff0c;如何插入SEI自定義數據 一、什么是SEI&#xff1f; SEI&#xff08;Supplemental Enhancement Information&#xff0c;補充增強信息&#xff09;是H.264/H.265視頻編碼標準中的一種元數據載體&#xff0c;它允許在視頻流中嵌入額外的信息&#xff0c;如時…

為什么分類任務偏愛交叉熵?MSE 為何折戟?

在機器學習的世界里&#xff0c;損失函數是模型的“指南針”——它定義了模型“好壞”的標準&#xff0c;直接決定了參數優化的方向。對于分類任務&#xff08;比如判斷一張圖片是貓還是狗&#xff09;&#xff0c;我們通常會選擇交叉熵作為損失函數&#xff1b;而在回歸任務&a…

[echarts]橫向柱狀圖

前言 接到一個需求&#xff0c;需要展示一個橫向的柱狀圖&#xff0c;按數量從大到小排序&#xff0c;并定時刷新 使用react配合echarts進行實現。 react引入echarts import React, { useEffect, useRef } from react; import * as echarts from echarts; import DeviceApi fro…

【開源項目】輕量加速利器 HubProxy 自建 Docker、GitHub 下載加速服務

??引言?? 如果你經常被 Docker 鏡像拉取、GitHub 文件下載的龜速折磨&#xff0c;又不想依賴第三方加速服務&#xff08;擔心穩定性或隱私&#xff09;&#xff0c;今天分享的 ??HubProxy?? 可能正是你需要的。這個開源工具用一行命令就能部署&#xff0c;以極低資源消…

java web jsp jstl練習

JSP 的學習。 核心功能模塊 1. 源代碼層 &#xff08; src &#xff09; HelloWorld &#xff1a;主程序入口領域模型 &#xff1a; domain 包含User.java和ceshi.java控制器 &#xff1a; servlet 包含登錄驗證和驗證碼相關ServletWeb表現層 &#xff08; web &#xff09; JS…

VSCode 完全指南:釋放你的編碼潛能

零、簡介 在當今的軟件開發領域&#xff0c;代碼編輯器的選擇至關重要&#xff0c;它就像是工匠手中的工具&#xff0c;直接影響著工作效率和成果質量。Visual Studio Code&#xff08;簡稱 VSCode&#xff09;自問世以來&#xff0c;迅速在全球開發者社區中嶄露頭角&#xff…

《n8n基礎教學》第一節:如何使用編輯器UI界面

在本課中&#xff0c;你將學習如何操作編輯器界面。我們將瀏覽畫布&#xff0c;向您展示每個圖標的含義&#xff0c;以及在 n8n 中構建工作流程時在哪里可以找到您需要的東西。本課程基于 n8n 最新版本 。在其他版本中&#xff0c;某些用戶界面可能有所不同&#xff0c;但這不會…

gcc g++ makefile CMakeLists.txt cmake make 的關系

gcc&#xff1a;C語言編譯器g&#xff1a;C編譯器makefile&#xff1a;定義編譯規則、依賴關系和構建目標。可以手動編寫&#xff0c;也可以由CMakeLists.txt生成cmake&#xff1a;讀取CMakeLists.txt文件&#xff0c;生成Makefilemake&#xff1a;構建工具&#xff0c;執行Mak…

SFT 訓練器

SFT 訓練器 “訓練時間到!” 我們現在終于可以創建一個監督微調訓練器的實例了: trainer = SFTTrainer( model=model, processing_class=tokenizer, args=sft_config, train_dataset=dataset, )SFTTrainer 已經對數據集進行了預處理,因此我們可以深入查看,了解每個小批次…

Android Material Components 全面解析:打造現代化 Material Design 應用

引言 在當今移動應用開發領域&#xff0c;用戶體驗(UX)已成為決定應用成功與否的關鍵因素之一。Google推出的Material Design設計語言為開發者提供了一套完整的視覺、交互和動效規范&#xff0c;而Material Components for Android(MDC-Android)則是將這些設計理念轉化為可重用…

Windows使用Powershell自動安裝SqlServer2025服務器與SSMS管理工具

安裝結果: 安裝前準備: 1.下載mssql server 2025安裝器 2.下載iso鏡像 3.下載好SSMS安裝程序,并放到iso同目錄下 4.執行腳本開始自動安裝

09 RK3568 Debian11 ES8388 模擬音頻輸出

1、設備樹配置 確認自己的i2c,使用sdk帶的驅動es8323 /SDK/kernel/sound/soc/codecs/es8323.c es8388_sound: es8388-sound {status = "okay";compatible = "rockchip,multicodecs-card"; rockchip,card-name = "rockchip,es8388-codec"; …

力扣-199.二叉樹的右視圖

題目鏈接 199.二叉樹的右視圖 class Solution {public List<Integer> rightSideView(TreeNode root) {List<Integer> res new ArrayList<>();Queue<TreeNode> queue new LinkedList<>();if (root null)return res;queue.offer(root);while …

Android Bitmap 完全指南:從基礎到高級優化

在 Android 開發中&#xff0c;圖像處理是一個核心且復雜的領域&#xff0c;而 Bitmap 作為 Android 中表示圖像的基本單位&#xff0c;貫穿了從簡單圖片顯示到復雜圖像編輯的各個場景。然而&#xff0c;Bitmap 處理不當往往會導致應用性能下降、內存溢出&#xff08;OOM&#…

unity日志過濾器

背景&#xff1a;之前做游戲的時候和同組的同事聊過說日志過濾盡量不要限制大家怎么使用日志打印的接口&#xff0c;不要加額外的參數&#xff0c;比如多加一個標簽string,或者使用特定的接口&#xff0c;枚舉。最好就是日志大家還是用Debug.Log無感去用&#xff0c;然后通過勾…

OpenGL Camera

一. lookAt函數的參數含義glm::mat4 view glm::lookAt(cameraPos, // 相機在世界坐標系中的位置&#xff08;任意值&#xff09;cameraPos cameraFront, // 相機看向的目標點&#xff08;位置朝向&#xff09;cameraUp // 相機的"上方向"&#xff08;通…