《算法系列》之双指针

2024-02-25 20:20
文章标签 算法 指针 系列 之双

本文主要是介绍《算法系列》之双指针,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介

  双指针并不是一种数据结构,也不是指C这种语言中的指针,而是一种经典的算法思想,可以用来求链表的中点链表是否成环移除数组中多余的元素归并排序 等,核心思想是:设计不同速度、不同间距、或不同方向的两个指针对目标集合操作,解决我们的问题

理论基础

  双指针是一种通过设置两个指针不断进行单向移动来解决问题的算法思想。一般包含两种形式:一、两个指针指向同一个序列。二、两个指针分别指向不同的序列。指向同一序列的比较常见,代表有快慢指针首尾指针固定间距指针等。指向不同序列的双指针代表有归并排序这种,需要合并时用双指针或者多指针。
在这里插入图片描述

解题心得

  • 双指针并不是数据结构,也不是指C这种语言中的指针,而是一种解题思想。
  • 很多时候双指针的题,会有多种解法,但双指针解法往往是最清晰易懂的解法。
  • 双指针可用来提高效率,一般是将O(n^2)的时间复杂度,降为O(n)。
  • 解题时要注意两指针索引的更新。

算法题目

11. 盛最多水的容器

在这里插入图片描述
题目解析:从两端开始选择左右两边的柱子,比当前低的柱子不用计算,因为面积一定更小。
代码如下:

/*** 双指针*/
class Solution {public int maxArea(int[] height) {int maxArea = 0;// 左边柱子索引int l = 0;// 右边柱子索引int r = height.length - 1;while (l < r) {maxArea = Math.max(maxArea, Math.min(height[l], height[r]) * (r - l));int tmp = 0;if (height[l] < height[r]) {tmp = height[l++];// 如果新柱子没有原来的柱子高,则一定没有原来面积大,不用计算与比较,直接索引加1while (tmp > height[l]) {l++;}} else {tmp = height[r--];// 如果新柱子没有原来的柱子高,则一定没有原来面积大,不用计算与比较,直接索引减1while (tmp > height[r]) {r--;}}}return maxArea;}
}
15. 三数之和

在这里插入图片描述
题目解析:采用排序加双指针的方法计算结果。
代码如下:

/*** 双指针*/
class Solution {public List<List<Integer>> threeSum(int[] nums) {// 升序排序// -4 -1 -1 0 1 2Arrays.sort(nums);List<List<Integer>> res = new ArrayList<>();for (int i = 0; i < nums.length; i++) {// 第一个数都大于0,其余的数相加,不可能为0,故直接返回if (nums[i] > 0) {return res;}// 两个数相等,直接前进一位,解决重复问题if (i > 0 && nums[i] == nums[i - 1]) {continue;}// 两个指针分别从 i + 1 和 nums.length - 1 开始向彼此靠拢int left = i + 1;int right = nums.length - 1;while (right > left) {int sum = nums[i] + nums[left] + nums[right];if (sum > 0) {right--;} else if (sum < 0) {left++;} else {res.add(Arrays.asList(nums[i], nums[left], nums[right]));// 两个数相等,直接前进一位,解决重复问题while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;right--;left++;}}}return res;}
}
16. 最接近的三数之和

在这里插入图片描述
题目解析:排序后,用左右双指针解题。
代码如下:

/*** 双指针*/
class Solution {public int threeSumClosest(int[] nums, int target) {// 升序排序Arrays.sort(nums);// 初始化结果值int res = nums[0] + nums[1] + nums[2];for (int i = 0; i < nums.length; i++) {// 两个指针分别从 i + 1 和 nums.length - 1 开始向彼此靠拢int left = i + 1;int right = nums.length - 1;while (right > left) {int sum = nums[i] + nums[left] + nums[right];// res 值取离target最近的sum值if (Math.abs(res - target) > Math.abs(sum - target)) {res = sum;}if (sum > target) {right--;} else if (sum < target){left++;} else if (sum == target){return res;}}}return res;}
}
18. 四数之和

在这里插入图片描述
题目解析:采用排序加双指针的方法计算结果,在三数之和的基础上加一层循环。
代码如下:

/*** 双指针*/
class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {// 升序排序Arrays.sort(nums);int len = nums.length;List<List<Integer>> res = new ArrayList<>();// 不足四个数,返回为空if (nums == null || len < 4) {return res;}for (int i = 0; i < len -3; i++) {// 两个数相等,直接前进一位,解决重复问题if (i > 0 && nums[i] == nums[i-1]) {continue;}// 剪枝// 最小四个值都大于目标值,则此后无结果if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {break;}// 最大四个值小于目标值,则本轮无结果,下一轮可能会有结果if (nums[i] + nums[len - 1] + nums[len - 2] + nums[len - 3] < target) {continue;}for (int j = i + 1; j < len -2; j++) {if (j > i + 1 && nums[j - 1] == nums[j]) {continue;}// 剪枝if(nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target){break;}if(nums[i] + nums[j] + nums[len - 2] + nums[len - 1] < target){continue;}// 两个指针分别从 j + 1 和 len - 1 开始向彼此靠拢int left = j + 1;int right = len - 1;while (right > left) {int sum = nums[i] + nums[j] + nums[left] + nums[right];if (sum > target) {right--;} else if (sum < target) {left++;} else {res.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;left++;right--;}}}}return res;}
}
19. 删除链表的倒数第 N 个结点

在这里插入图片描述
题目解析:用快慢双指针,第一个指针位置为x,第二个指针为 x + n。
代码如下:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*//*** 双指针*/
class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {ListNode curr = head;ListNode pre = head;for (int i = 0; i < n; i++) {// 如果 right.next 为空,则说明,n为链表长度,删除位置为头结点if (pre.next != null) {pre = pre.next;} else {return head.next;}}// curr 前进到需要删除的节点while (pre.next != null) {curr = curr.next;pre = pre.next;}// 删除节点curr.next = curr.next.next;return head;}
}
26. 删除有序数组中的重复项

在这里插入图片描述
题目解析:用快慢指针,重复时,fast指针前进一位,low指针不变。。
代码如下:

/*** 双指针*/
class Solution {public int removeDuplicates(int[] nums) {if(nums == null && nums.length == 0){return 0;}int low = 0;for(int fast =0 ; fast < nums.length; fast++ ){if(nums[low] != nums[fast]){low += 1;nums[low] = nums[fast];  }}return low + 1;}
}
27. 移除元素

在这里插入图片描述
题目解析:使用快慢指针,出现目标值val,fast进一位,low不动即可。
代码如下:

/*** 双指针*/
class Solution {public int removeElement(int[] nums, int val) {if(nums == null && nums.length == 0){return 0;}// low fastint l = 0;for(int f = 0; f<nums.length; f++){if(nums[f] != val){nums[l] = nums[f];l++;}}return l;}
}
31. 下一个排列

在这里插入图片描述
题目解析:从右往左找到第一个不再递增的位置,然后在右边找到刚好大于当前位的数字即可。
代码如下:

/*** 双指针*/
class Solution {public void nextPermutation(int[] nums) {int i = nums.length - 2;// 找到第一个不再递增的位置while (i >= 0 && nums[i + 1] <= nums[i]) {i--;}// 如果找到最左边,倒置输出if (i < 0) {reverse(nums, 0);return;}// 找到刚好大于nums[i]的位置int j = nums.length - 1;while (j >= 0 && nums[j] <= nums[i]) {j--;}// 交换swap(nums, i, j);reverse(nums, i + 1);}private void swap(int[] nums, int i, int j) {int temp = nums[j];nums[j] = nums[i];nums[i] = temp;}private void reverse(int[] nums, int start) {int i = start, j = nums.length - 1;while (i < j) {swap(nums, i, j);i++;j--;}}
}
61. 旋转链表

在这里插入图片描述
题目解析:先测出链表的长度,然后用K值取余,再用长度 - K值,将剩余链表和头节点拼接。
代码如下:

/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*//*** 双指针*/
class Solution {public ListNode rotateRight(ListNode head, int k) {ListNode res = null;ListNode curr = head;ListNode tail = head;// 特殊情况,直接返回if (head == null || head.next == null) {return head;}// 测出链表的长度int len = 1;while (tail.next != null) {len++;tail = tail.next;}// 如果k长度为len的整数倍,直接返回headif (k % len == 0) {return head;}// len - 对K值取余 - 1,为断开处int index = len - k % len - 1;// 找到断开处while (index != 0) {curr = curr.next;index--;}// 断开res = curr.next;curr.next = null;// 拼接tail.next = head;return res;}
}
75. 颜色分类

在这里插入图片描述
题目解析:左右双指针,如果等于1则不管,等于0,则向头部交换,等于2则向尾部交换。
代码如下:

/*** 双指针*/
class Solution {public void sortColors(int[] nums) {int index = 0;int l = -1;int r = nums.length;while(index < r){// 当前数等于1则不变if(nums[index]==1){index++;// 当前数等于0,则和头部交换}else if(nums[index] == 0){swap(nums,index++,++l);// 当前数等于2,则和尾部交换}else if(nums[index] == 2){swap(nums,index,--r);}}}public void swap(int[] arr,int a,int b){int temp = arr[a];arr[a] = arr[b];arr[b]=temp;}
}
80. 删除有序数组中的重复项 II

在这里插入图片描述
题目解析:只能原地修改数组,最多使用O(1)额外空间,故:用新的数组覆盖旧数组即可。
代码如下:

/*** 双指针*/
class Solution {public int removeDuplicates(int[] nums) {if (nums.length == 0 || nums.length == 1 || nums.length == 2) {return nums.length;}int res = 1;for (int i = 2; i < nums.length; i++) {if (nums[i] == nums[res] && nums[i] == nums[res - 1]) {} else {res++;nums[res] = nums[i];}}return res + 1;}
}
82. 删除排序链表中的重复元素 II

在这里插入图片描述
题目解析:一个指针前进,一个指针记录不重复的节点即可。
代码如下:

/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*//*** 双指针*/
class Solution {public ListNode deleteDuplicates(ListNode head) {// 虚拟头节点ListNode dummyHead = new ListNode();ListNode temp = dummyHead;while (head != null) {if (head.next != null && head.val == head.next.val) {int i = head.val;// 如当前节点值重复,则把等于当前值的节点,全部跳过,即跳过了所有重复的节点while (head != null && head.val == i) {head = head.next;}} else {// 记录temp.next = new ListNode(head.val);temp = temp.next;head = head.next;}}return dummyHead.next;}
}
86. 分隔链表

在这里插入图片描述
题目解析:声明两个链表,一个记录小于x的值,一个记录大于等于x的值,最后拼接即可。
代码如下:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*//*** 双指针*/
class Solution {public ListNode partition(ListNode head, int x) {ListNode dummyHead1 = new ListNode(0);ListNode dummyHead2 = new ListNode(0);ListNode node1 = dummyHead1;ListNode node2 = dummyHead2;while (head != null) {// 记录小于x的值if (head.val < x) {node1.next = head;head = head.next;node1 = node1.next;node1.next = null;// 记录大于等于x的值} else {node2.next = head;head = head.next;node2 = node2.next;node2.next = null;}}node1.next = dummyHead2.next;return dummyHead1.next;}
}
88. 合并两个有序数组

在这里插入图片描述
题目解析:从后往前,进行归并。选择最大的数放在nums1最后一位。
代码如下:

/*** 双指针*/
class Solution {public void merge(int[] nums1, int m, int[] nums2, int n) {int i = m-- + n--;// 如果nums2不为空则继续while (n >= 0) {nums1[--i] = m >= 0 && nums1[m] >= nums2[n] ? nums1[m--] : nums2[n--]; }}
}
125. 验证回文串

在这里插入图片描述
题目解析:先去除字符和数字以外的字符,再用双指针比较。
代码如下:

/*** 双指针*/
class Solution {public boolean isPalindrome(String s) {int n = s.length();int l = 0, r = n - 1;while (l < r) {while (l < r && !Character.isLetterOrDigit(s.charAt(l))) {l++;}while (l < r && !Character.isLetterOrDigit(s.charAt(r))) {r--;}if (l < r) {if (Character.toLowerCase(s.charAt(l)) != Character.toLowerCase(s.charAt(r)))return false;}r--;l++;}return true;}
}
141. 环形链表

在这里插入图片描述
题目解析:经典快慢指针,指针能相遇,则说明有环。
代码如下:

/*** Definition for singly-linked list.* class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*//*** 快慢指针*/
public class Solution {public boolean hasCycle(ListNode head) {ListNode fast = head;ListNode slow = head;while (fast != null && fast.next != null) {// 快指针,一次前进两步fast = fast.next.next;// 慢指针,一次移动一步slow = slow.next;// 快慢指针能相遇,则说明有环if (fast == slow) {return true;}}// 正常到链尾,则无环return false;}
}
142. 环形链表 II

在这里插入图片描述
题目解析:解析如下

快慢指针,快慢指针能相遇,则说明有环。第一次相遇时:7<-6<- 5|     ^|     |0->1->2->3->4[-----]a
设置快慢两个指针,fast, slow fast一次前进两步,slow一次前进一步,
设a为第一个节点到入环节点的距离。 a = [0->2]
设b为入环口到相遇点的距离。b = [2->6]
设c为相遇点到入环口的距离。c = [6->2]
当fast,和slow相遇的时候,fast经过的节点是slow的两倍,设slow经过的节点数为S
则有:S=a+b ,2S=a+b+c+b,化解得:2(a+b) = a+b+c+b --> 2a+2b = a+b+c+b --> 2a = a+c --> a =c
则分别从头节点、相遇点出发至下一个相遇点,即为入环口点

代码如下:

/*** Definition for singly-linked list.* class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*//*** 双指针*/
public class Solution {public ListNode detectCycle(ListNode head) {ListNode fast = head;ListNode slow = head;boolean hasCycle = false;while (fast != null && fast.next != null) {// 快指针,一次前进两步fast = fast.next.next;// 慢指针,一次移动一步slow = slow.next;// 快慢指针能相遇,则说明有环if (fast == slow) {hasCycle = true;break;}}// 若有环,找到入口点// 从head和相遇点同时出发,再次相遇时,即为入口点if (hasCycle) {ListNode temp = head;while (slow != temp) {slow = slow.next;temp = temp.next;}return temp;} else {return null;}}
}
143. 重排链表

在这里插入图片描述
题目解析:先用双指针找到链表中点,再反转后半段链表,最后合并两段链表即可。
代码如下:

/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*//*** 双指针*/
class Solution {public void reorderList(ListNode head) {if (head == null || head.next == null) {return;}// 用双指针找到链表中点ListNode slow = head;ListNode fast = head;while (fast.next != null && fast.next.next != null) {slow = slow.next;fast = fast.next.next;}// 反转后半段链表,并与后半段分开ListNode left = head;// 反转ListNode right = helper(slow.next);slow.next = null;// 合并两段链表while (left != null && right != null) {ListNode t1 = left.next;ListNode t2 = right.next;left.next = right;left = t1;right.next = t1;right = t2;}}// 直接用插入虚拟节点后的方式反转链表,再返回头节点public ListNode helper(ListNode head) {ListNode dummyHead = new ListNode(0);ListNode cur = head;ListNode next = null;while (cur != null) {next = cur.next;cur.next = dummyHead.next;dummyHead.next = cur;cur = next;}return dummyHead.next;}
}
151. 翻转字符串里的单词

在这里插入图片描述
题目解析:首先去除所有空格,再反转整个字符串,再单独反转每个单词。
代码如下:

/*** 双指针*/
class Solution {public String reverseWords(String s) {// 1.去除首尾以及中间多余空格StringBuilder sb = removeSpace(s);// 2.反转整个字符串reverseString(sb, 0, sb.length() - 1);// 3.反转各个单词reverseEachWord(sb);return sb.toString();}private StringBuilder removeSpace(String s) {int start = 0;int end = s.length() - 1;while (s.charAt(start) == ' ') start++;while (s.charAt(end) == ' ') end--;StringBuilder sb = new StringBuilder();while (start <= end) {char c = s.charAt(start);if (c != ' ' || sb.charAt(sb.length() - 1) != ' ') {sb.append(c);}start++;}return sb;}/*** 反转字符串指定区间[start, end]的字符*/public void reverseString(StringBuilder sb, int start, int end) {while (start < end) {char temp = sb.charAt(start);sb.setCharAt(start, sb.charAt(end));sb.setCharAt(end, temp);start++;end--;}}private void reverseEachWord(StringBuilder sb) {int start = 0;int end = 1;int n = sb.length();while (start < n) {while (end < n && sb.charAt(end) != ' ') {end++;}reverseString(sb, start, end - 1);start = end + 1;end = start + 1;}}
}
160. 相交链表

在这里插入图片描述
在这里插入图片描述
题目解析:当pA和pB分别前进到队尾未相遇时,pA指前B队头,pB指前A队头。继续前进,此时若地址能相等,则为交点。因为若两条链表相交,此时两指针前行的距离刚好一致。若行驶最后两指针都为null则不相交。
代码如下:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*//*** 双指针*/
public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {if (headA == null || headB == null) {return null;}ListNode pA = headA, pB = headB;while (pA != pB) {pA = pA == null ? headB : pA.next;pB = pB == null ? headA : pB.next;}return pA;}
}
167. 两数之和 II - 输入有序数组

在这里插入图片描述
题目解析:用二分法加指针解题即可。
代码如下:

/*** 双指针*/
class Solution {public int[] twoSum(int[] numbers, int target) {int i = 0, j = numbers.length - 1;while (i < j) {int m = (i + j) >>> 1;if (numbers[i] + numbers[m] > target) {j = m - 1;} else if (numbers[m] + numbers[j] < target) {i = m + 1;} else if (numbers[i] + numbers[j] > target) {j--;} else if (numbers[i] + numbers[j] < target) {i++;} else {return new int[]{i + 1, j + 1};}}return new int[]{0, 0};}
}
189. 轮转数组

在这里插入图片描述
题目解析:翻转整个数组,翻转反转k个区间,再反转剩余区间。
代码如下:

/*** 双指针*/
class Solution {public void rotate(int[] nums, int k) {k %= nums.length;reverse(nums, 0, nums.length - 1);reverse(nums, 0, k - 1);reverse(nums, k, nums.length - 1);}public void reverse(int[] nums, int start, int end) {while (start < end) {int temp = nums[start];nums[start] = nums[end];nums[end] = temp;start += 1;end -= 1;}}
}
234. 回文链表

在这里插入图片描述
题目解析:先从中分成两条链,然后反转后半段,然后依次比较,只要一个值不相等,则返回false。
代码如下:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*//*** 双指针*/
class Solution {public boolean isPalindrome(ListNode head) {// 为空直接返回if (head == null || head.next == null) {return true;}// 找到中点ListNode fast = head;ListNode slow = head;while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}// 反转后半段ListNode cur = slow.next;while (cur != null) {ListNode curNext = cur.next;cur.next = slow;slow = cur;cur = curNext;}// 判断是否是回文while(head != slow){if(head.val != slow.val){return false;}if(head.next == slow){return true;}head = head.next;slow = slow.next;}return true;}
}
283. 移动零

在这里插入图片描述
题目解析:low指针指向非零数的个数,fast循环整个数组,每次把fast位置上的数字交换过来即可。
代码如下:

/*** 双指针*/
class Solution {public void moveZeroes(int[] nums) {int low = 0;for (int fast = 0; fast < nums.length; fast++) {if (nums[fast] != 0) {if (low < fast) {nums[low] = nums[fast];nums[fast] = 0;}low++;}}}
}
287. 寻找重复数

在这里插入图片描述
题目解析:可抽象为成环链表找入口问题,nums[slow] 表示取指针对应的元素,注意 nums 数组中的数字都是在 1 到 n 之间的(在数组中进行游走不会越界),入口处即为重复元素。
代码如下:

/*** 双指针 */
class Solution {public int findDuplicate(int[] nums) {int fast = 0, slow = 0;while(true) {// fast 前进两步,slow前进一步fast = nums[nums[fast]];slow = nums[slow];// 相遇时,fast从入口出发,再次与slow相遇时,即为环入口,也为重复数if(slow == fast) {fast = 0;while(nums[slow] != nums[fast]) {fast = nums[fast];slow = nums[slow];}return nums[slow];}}}
}
回到首页

刷 leetcode 500+ 题的一些感受

下一篇

《算法系列》之栈

这篇关于《算法系列》之双指针的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/746594

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言