代码随想录--双指针章节总结

news2024/11/27 4:22:21

代码随想录–双指针章节总结

1.LeetCode27 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

数组的元素是不能删的,只能覆盖。

这个题需要注意的在数组中元素的删除实际上是通过覆盖来完成的

比如[1,2,3,4,5] 现在删除数组中4的元素,那么实际上是将4后面的元素都向前移动一个单位,把4覆盖掉,的到[1,2,3,5,5],返回的数组长度-1

解题思路1(暴力法):使用两个for循环。第一个循环用来循环遍历整个数组,第二个用来移动元素。

public int removeElement(int[] nums, int val) {
  if (nums == null || nums.length == 0)
      return 0;
  int size = nums.length;
  for (int i = 0; i < size; i++) {
      if (nums[i] != val)
        continue;

      for (int j = i; j < size - 1; j++) {
          nums[j] = nums[j + 1];
      }
      size--;
      i--; // 这个需要特别注意,因为我们覆盖元素,实际上就是将后面的元素都向前移动一位,那么i也要向前移动,否则会漏掉一些元素
  }
  return size;
}

解题思路2(利用快慢指针):首先需要明确快慢指针代表什么意思:

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组。
  • 慢指针:指向更新新数组下标的位置

快指针从头开始遍历数组,只要发现不等于给定val的元素,就将元素赋值为slow指针指向的位置。这样循环结束后,所有的不等于val的元素都保存起来

public int removeElement(int[] nums, int val) {
  if (nums == null || nums.length == 0)
      return 0;
  int fast = 0, slow = 0;
  for (fast = 0; fast < nums.length; fast++) {
      if (nums[fast] != val) {
          nums[slow] = nums[fast];
          slow++;
      }
  }
  return slow;
}

2.LeetCode344 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]

解题思路: 直接使用双指针,分别从数组的第一个和最后一个元素进行遍历,然后交换这两个元素即可。

public void reverseString(char[] s) {
    int left = 0, right = s.length - 1;
    while (left < right) {
        char temp = s[left];
        s[left++] = s[right];
        s[right--] = temp;
    }
}

3.剑指offer05 替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例 1:
输入:s = "We are happy."
输出:"We%20are%20happy."

解题思路1: 直接使用StringBuilder,遍历数组,只要发现有空格,就向StringBuilder中append%20,否则就把原来字符串中字符append。

public static String replaceSpace(String s) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < s.length(); i++) {
        // 这个地方比较的是字符相等不相等
        // if (" ".equals(s.charAt(i)))
        if (s.charAt(i) == ' ') {
            sb.append("%20");
            continue;
        }
        sb.append(s.charAt(i));
    }
    return sb.toString();
}

这个地方需要注意这个条件" ".equals(s.charAt(i))使用charAt(i)函数返回的是一个char,因此应该用==而不是equal方法

解题思路2: 使用双指针

  • 首先遍历整个字符串,统计空格个数
  • 然后按照空格个数,将字符串进行扩容
  • 然后i,j指针分别指向扩容前数组最后的元素,和扩容后数组的元素
  • 然后开始遍历,如果s[i]不是空格,则s[j] = s[i]
  • 如果是空格,则s[i] = '0';s[i - 1] = '2';s[i - 2] = '%';
  • 直到i==j停止循环。

image-20230120164523735

因为在Java中字符串是常量,因此这道题无法像C++一样直接操作字符串中的字符,但是这个思路是可以在Java中实现的,但是就是实际上还没有方法一效率高。

public class Main {
    public static void main(String[] args) {
        String s = "We are happy.";
        replaceSpace(s);
    }
    public static void replaceSpace(String s) {
        char[] chars = s.toCharArray();
        if (chars.length == 0)
            return;
        // 遍历数组,查找空格次数
        int count = 0;
        for (char c : chars) {
            if (c == ' ')
                count++;
        }
        char[] expand = expand(chars, chars.length + 2 * count);
        // 定义两个指针
        int p1 = chars.length - 1, p2 = expand.length - 1;

        while (p1 != p2) {
            // 判断p1指向的是空格字符
            if (expand[p1] != ' ') {
                expand[p2--] = expand[p1--];
            } else if (expand[p1] == ' ') {
                expand[p2] = '0';
                expand[p2 - 1] = '2';
                expand[p2 - 2] = '%';
                p2 -= 3;
                p1--;
            }
        }
        for (int i = 0; i < expand.length; i++) {
            System.out.print(expand[i]);
        }
    }

    /**
     * 数组扩容
     *
     * @param src 原数组
     * @param len 新数组长度
     * @return 新数组
     */
    private static char[] expand(char[] src, int len) {
        char[] expand = new char[len];
        for (int i = 0; i < src.length; i++) {
            expand[i] = src[i];
        }
        return expand;
    }
}

4.Leetcode151 反转单词

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

示例 1:
输入:s = "the sky is blue"
输出:"blue is sky the"
示例 2:
输入:s = "  hello world  "
输出:"world hello"
解释:反转后的字符串中不能存在前导空格和尾随空格。
示例 3:
输入:s = "a good   example"
输出:"example good a"
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。

解题思路1

  • 使用trim函数取出字符串开头和结尾的空格
  • 使用split分割单词,形成一个string[], 每一个元素是一个单词
  • 然后反转string[]数组即可。
public String reverseWords(String s) {
    // 如果一个字符串中有多个连续的空格
    // trim()的作用
    String[] strings = s.trim().split(" ");
    int left = 0, right = strings.length - 1;
    // 反转数组
    while (left < right) {
        String temp = strings[left];
        strings[left++] = strings[right];
        strings[right--] = temp;
    }
    // 构建字符串
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < strings.length; i++) {
        if ("".equals(strings[i]))
            continue;
        if (i == strings.length - 1) {
            sb.append(strings[i]);
            continue;
        }
        sb.append(strings[i] + " ");
    }
    return sb.toString();
}

这里需要特别注意的是,如果String str = " hello world ";,那么使用split(" ")之后的得到的数组是:

image-20230120174654062

所以需要在添加到StringBuilder中忽略掉这些空字符串。

第二个需要注意的是,如果想去除掉字符串开头和结尾的空格,可以使用str.trim()函数

解题思路2: 将字符串先整体反转一次,然后在每一个单词内部反转一次,就可以得到最终的结果。这个地方的难点是因为给的字符串可能在开头和结尾都包含若干个空格,以及每一个单词之间还有可能存在多个空格,所以需要删除掉字符串中额外的空格。

public String reverseWords(String s) {
    // 判断字符串是否为空
    if (s == null || s.length() == 0) return null;
    // 去除掉字符串中额外的空格
    char[] chars = s.toCharArray();
    chars = removeExtraSpaces(chars).toCharArray();
    // 整体反转字符串
    reverse(chars, 0, chars.length - 1);
    // 每一个单词反转一次
    int start = 0; // 记录每一个单词开始的下标
    for (int i = 0; i <= chars.length; i++) {
        if (i == chars.length || chars[i] == ' ') {
            // 反转单词
            reverse(chars, start, i - 1);
            start = i + 1;
        }
    }
    return new StringBuilder().append(chars).toString();
  }

  // 字符串反转
  private void reverse(char[] chars, int start, int end) {
      while (start < end) {
          char temp = chars[start];
          chars[start++] = chars[end];
          chars[end--] = temp;
      }
  }

  // 删除所有额外的空格
  private String removeExtraSpaces(char[] chars) {
    // 定义快慢指针
    int slow = 0;
    // 开始遍历
    for (int fast = 0; fast < chars.length; fast++) {
        // 只要fast遍历的不是空格
        if (chars[fast] != ' ') {
            // 每一个单词前面添加空格,首单词不添加空格
            if (slow != 0) chars[slow++] = ' ';
            // 复制整个单词
            while (fast < chars.length && chars[fast] != ' ') {
                chars[slow++] = chars[fast++];
            }
        }
    }
    return new StringBuilder().append(chars, 0, slow).toString();
}

image-20230120202653860

for (int i = 0; i < chars.length; i++) {
 if (chars[i] == ' ') {
     // 第一个单词遍历完毕
     reverse(chars, rec, i - 1);
     rec = i + 1;
 }
}

需要注意的是,在进行单词内部反转的时候,我们在条件上不能写上面的这种。判断只要有空格,那么就反转之间的单词。如果这样写,就会发现最后一个单词实际上没有反转。

原因是最后一个单词后面没有空格,但是也要反转。下面的这种写法才对。当执行到最后一个元素的时候,也要反转。

为什么是i<=chars.length,是因为要反转的区间是[rec, i - 1] 所以i必须执行到=chars.length

for (int i = 0; i <= chars.length; i++) {
   if (i == chars.length || chars[i] == ' ') {
       // 第一个单词遍历完毕
       reverse(chars, rec, i - 1);
       rec = i + 1;
   }
}

这里面还有一个很坑的细节问题

if (i == chars.length || chars[i] == ' ') {
    // 反转单词
    reverse(chars, start, i - 1);
    start = i + 1;
}

i == chars.length || chars[i] == ' '这个条件一定不能写成chars[i] == ' ' || i == chars.length 因为假设数组下标区间是[0,3] 长度为4,我们本意是条件是长度为4或者chars[i] == ' '都可以

但是如果按照chars[i] == ' ' || i == chars.length 这个条件写的,假设i=4,那么在判断第一个条件的时候,直接数组越界,第二个条件不会判断,算法出错。!!因此必须要反过来写才可以

5. LeetCode206 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:img

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

解题思路:使用两个指针来做

反转链表实际上就是将每一个链表的next指针指向前驱结点。因此可以定义两个指针,一个是pre指向当前遍历元素的前驱结点,初始值为null,因为第一个结点反转后,变成最后一个结点,而最后一个结点的next正好是null。cur指向当前正在遍历的结点

在循环中执行下面的操作

  • 使用temp保存当前遍历元素的next指针
  • 然后将当前元素的next指针赋值为pre
  • 然后将per=cur
  • 最后cur=cur.next

注意:这里一定要将cur.next先使用temp保存起来,否则因为在第二步cur.next值已经被修改了,再次访问cur=cur.next就不对了。

public ListNode reverseList(ListNode head) {
    // 如果链表为空,则返回空
    if (head == null) return null;
    // 如果链表中只有只有一个元素,则直接返回
    if (head.next == null) return head;

    ListNode pre = null, cur = head;
    ListNode temp;
    while (cur != null) {
        temp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = temp;
    }
    return pre;
}

注意最后的返回值不要写成下面这两种

  • 写成head,head指向的是原始链表的头结点1,如果返回head,则返回的实际上是反转后链表的最后一个元素
  • 写成cur,while退出后,cur==null,所以会返回null

正确的是应该返回pre

解题思路2: 只要是反转顺序的都可以考虑用栈来做。

  • 首先将所有的结点入栈
  • 然后创建一个虚拟虚拟头结点,让cur指向虚拟头结点。然后开始循环出栈,每出来一个元素,就把它加入到以虚拟头结点为头结点的链表当中,最后返回即可。
public ListNode reverseList(ListNode head) {
    // 如果链表为空,则返回空
    if (head == null) return null;
    // 如果链表中只有只有一个元素,则直接返回
    if (head.next == null) return head;

    // 创建栈 每一个结点都入栈
    Stack<ListNode> stack = new Stack<>();
    ListNode cur = head;
    while (cur != null) {
        stack.push(cur);
        cur = cur.next;
    }

    // 创建一个虚拟头结点
    ListNode pHead = new ListNode(0);
    cur = pHead;
    while (!stack.isEmpty()) {
        ListNode node = stack.pop();
        cur.next = node;
        cur = cur.next;
    }
    // 最后一个元素的next要赋值为空
    cur.next = null;

    return pHead.next;

}

采用这种方法需要注意一点。就是当整个出栈循环结束以后,cur正好指向原来链表的第一个结点,而此时结点1中的next指向的是结点2,因此最后还需要cur.next = null

image-20230117202045647

6. LeetCode19 删除链表的倒数第N个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

img

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

解题思路: 使用快慢指针,快指针先走N步,然后快慢指针同时走,最终当快指针指向链表中最后一个元素时,慢指针正好指向倒数N个结点的前一个结点。然后进行删除即可。

这里需要注意n给的值可能不合法的情况。

public ListNode removeNthFromEnd(ListNode head, int n) {
    if (head == null) return null;
    // 定义快慢指针
    ListNode pHead = new ListNode(0);
    pHead.next = head;
    ListNode slow = pHead, fast = pHead;
    for (int i = 1; i <= n; i++) {
          // n不合法
    if (fast == null) return null;
        fast = fast.next;
    }
    while (fast.next != null) {
        fast = fast.next;
        slow = slow.next;
    }
    slow.next = slow.next.next;
    return pHead.next;
}

image-20230117215346273

和这个题类似的,找到链表中倒数第K个元素。

public ListNode FindKthToTail(ListNode pHead, int k) {
    // write code here
    ListNode fast = pHead;
    ListNode slow = pHead;

    for (int i = 0; i < k; i++) {
        // 需要注意的是 如果链表长度小于k的情况
        // 通过下面的if判断判断了链表为空的情况和链表长度小于k的情况
        if (fast == null)
            return null;
        fast = fast.next;
    }
    while (fast != null) {
        slow = slow.next;
        fast = fast.next;
    }
    return slow;
}

7. 面试题 02.07. 链表相交

输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:

img

可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。

解题思路:分别建立两个指针,从两个链表开始遍历,如果有公共结点,那么两个指针第一次相遇的时候就是第一个公共结点。

当链表1遍历到头结点后,将链表1的下一个指针指向链表2的头结点。

同理,当链表2遍历到头结点后,将链表1的下一个指针指向链表1的头结点。

36

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
  ListNode cur1 = headA;
  ListNode cur2 = headB;

  while (cur1 != cur2) {

      if (cur1 == null) {
          cur1 = headB;
          continue;
      }

      if (cur2 == null) {
          cur2 = headA;
          continue;
      }

      cur1 = cur1.next;
      cur2 = cur2.next;
  }
  return cur2;
}

有人可能会有疑问,如果链表中没有公共结点,则while会不会是死循环。实际上不会,因为如果没有公共结点,那么最终cur1 == cur2 == null

解题思路2: 利用双指针。

img

通过上面的图可以看到,如果我们使用两个指针同时指向两个链表的头结点。在两个链表长度相等的情况下,可以一一遍历。但是现在的情况是两个链表长度不相同,因此可以让长的链表指针先移动几位,和短链表的指针保持到同一个位置,然后两个指针同时遍历链表,并比较指向的元素是不是同一个即可。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  ListNode curA = headA;
  ListNode curB = headB;
  int lenA = 0, lenB = 0;
  // 求两个链表的长度
  while (curA != null) {
      lenA++;
      curA = curA.next;
    }
  while (curB != null) {
      lenB++;
      curB = curB.next;
  }
  curA = headA;
  curB = headB;

  if (lenA > lenB) {
      int gap = lenA - lenB;
      for (int i = 0; i < gap; i++) {
          curA = curA.next;
      }
  } else {
      int gap = lenB - lenA;
      for (int i = 0; i < gap; i++) {
          curB = curB.next;
      }
  }
  // 目前两个指针指向的位置是一样的 然后开始同时向前移动,然后判断两个指针指向的元素是不是一样
  // 如果一样,则返回元素
  System.out.print(1);
  while (curA != null || curB != null) {
      if (curA == curB)
          return curA;
      curA = curA.next;
      curB = curB.next;
  }
    return null;
}

解题思路3:可以利用set集合,将链表1中所有元素都保存到set中,然后遍历链表2,每遍历一个元素,就去set中看一看是否包含,如果包含则直接返回。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    if (headA == null) return null;
    // 创建一个set集合,保存链表A中所有元素
    Set<ListNode> set = new HashSet<>();
    ListNode cur = headA;
    while (cur != null) {
        set.add(cur);
        cur = cur.next;
    }

    // 遍历链表B
    cur = headB;
    while (cur != null) {
        if (set.contains(cur))
            return cur;
        cur = cur.next;
    }
    return null;
}

8. Leetcode142 环形链表II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

示例 1:

img

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

解题思路1: 这个方法很难想到,可以作为结论记录下来。

  • 首先定两个指针,一个快指针,一个满指针,都指向链表的头结点。快指针一次走两个元素,慢指针一次走一个元素。
  • 开始遍历,如果存在环,那么快慢指针一定会相遇。如果没有环,那么fast指针会率先指向null
  • 两个指针相遇后,再让满指针重新指向链表头结点,然后快慢指针同时一次移动一个单位。
  • 最后快慢指针再次相遇的时候,就是环中第一个结点位置。
public ListNode detectCycle(ListNode head) {
    if (head == null || head.next == null) return null;

    // 定义快慢指针
    ListNode fast = head, slow = head;

    // 注意这里的循环条件 因为要fast.next.next,所以一定要保证fast.next不为空
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow)
            break;
    }
    // 不存在环 这里的循环条件要和上面while相对应
    if (fast == null || fast.next == null) return null;

    slow = head;

    while (slow != fast) {
        slow =slow.next;
        fast =fast.next;
    }
    return slow;
}

如果单纯判断链表中是否有环,不需要返回环的入口结点,那么直接判断快慢指针是否会相遇即可。相遇则一定有环,否则就没有环。

解题思路2: 利用set集合。遍历链表,将元素存入set,在存入之间判断当前元素是否已经存在于set中,如果存在则直接返回该元素即可。

public ListNode detectCycle(ListNode head) {
    if (head == null || head.next == null) return null;

    Set<ListNode> set = new HashSet<>();
    ListNode cur= head;
    while (cur != null) {
        if (set.contains(cur))
            return cur;
        set.add(cur);
        cur = cur.next;
    }
    return null;
}

9.Leetcode15 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

解题思路:利用双指针解决

  • 判断数组中元素如果小于3,则直接返回
  • 对数组进行排序
  • 使用i遍历排序后的数组,如果arr[i]>0,则直接返回结果,因为是排好序的数组,所以i后面的肯定都>0
  • 对于重复的元素,直接跳过,判断条件是arr[i-1]=arr[i]
  • 让left指向i+1,right指向arr.len-1。判断arr[i] + arr[left] + arr[right] == 0
    • arr[i] + arr[left] + arr[right] > 0 right–
    • arr[i] + arr[left] + arr[right] < 0 left++
    • arr[i] + arr[left] + arr[right] = 0 找到了,同时对left和right去重
public List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> list = new ArrayList<>();
    // 如果数组中元素个数小于3,直接返回空
    if (nums.length < 3) return list;
    // 对数组元素排序
    Arrays.sort(nums);
    // 遍历数组
    for (int i = 0; i < nums.length; i++) {
        // 首先判断当前遍历的元素是否大于0,如果大于直接返回
        if (nums[i] > 0) return list;
        // 去重
        if (i > 0 && nums[i - 1] == nums[i]) continue;

        // 建立双指针
        int left = i + 1, right = nums.length - 1;
        while (left < right) {
            int sum = nums[i] + nums[left] + nums[right];
            if (sum > 0)
                right--;
            else if (sum < 0)
                left++;
            else {
                // 等于0
                list.add(Arrays.asList(nums[i], nums[left], nums[right]));
                // 去重
                while (left < right && nums[right - 1] == nums[right]) right--;
                while (left < right && nums[left] == nums[left + 1]) left++;
                left++;
                right--;
          }
      }
    }
    return list;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/177601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++程序设计——动态内存管理

一、C/C内存分布 1.栈&#xff08;堆栈&#xff09; 存储非静态局部变量、函数参数、返回值等等&#xff0c;栈是向下增长。 2.内存映射段 是高效的I/O映射方式&#xff0c;用于转载一个共享的动态内存库。用户可使用系统接口创建共享内存&#xff0c;做进程间通信。 3.堆 用…

WPS的简单JS宏应用

有一阵子没写博客了&#xff0c;各种琐事忙碌&#xff1b;前段时间接触了下WPS的宏功能&#xff0c;抽点时间写个学习笔记吧。 案例背景简单说一下&#xff0c;主任让我统计OA后台在建工程项目的概况&#xff0c;后台数据导出一张表&#xff0c;再问隔壁经营部的同事要了一张中…

java类的初始化2023018

类的初始化&#xff1a; 第一次使用某个类&#xff0c;例如Person类&#xff0c;系统通常会在第一次使用Person类时加载这个类并初始化这个类。在类的准备阶段&#xff0c;系统将会为该类的类变量分配内存空间&#xff0c;并指定默认初始值。当Person类初始化完成后&#xff0c…

机器学习笔记之深度玻尔兹曼机(二)深度玻尔兹曼机的预训练过程

机器学习笔记之深度玻尔兹曼机——深度玻尔兹曼机的预训练过程引言深度信念网络预训练过程的问题深度玻尔兹曼机的预训练过程(2023/1/24)引言 上一节介绍了玻尔兹曼机系列的相关模型&#xff0c;本节将介绍深度玻尔兹曼机的预训练过程。 深度信念网络预训练过程的问题 在玻尔…

Escher 愛雪磁磚設計法則 - 高雄燕巢深水國小科展指導

“Talk is cheap. Show me the code.” ― Linus Torvalds 老子第41章 上德若谷 大白若辱 大方無隅 大器晚成 大音希聲 大象無形 道隱無名 拳打千遍, 身法自然 “There’s no shortage of remarkable ideas, what’s missing is the will to execute them.” – Seth Godin …

GreenPlum AOCO列存如何将数据刷写磁盘

GreenPlum AOCO列存如何将数据刷写磁盘AOCO列存表每个字段一个文件&#xff0c;前面我们介绍了列存表如何加载数据页&#xff0c;本文我们重点介绍AOCO表如何进行刷写。AOCO表进行insert、update、delete会产生脏数据&#xff0c;和heap表的异步脏页刷写不同&#xff0c;AOCO表…

写一个锅炉温控系统用python编写

简单来说就是锅炉水热了之后循环泵自动开启,然后将热水输送走,送到暖气,热水抽走,凉水进入锅炉,温度降低,循环泵关闭,等待下一次水烧热。因为需要取暖的房子距离烧锅炉的地方比较远,所以需要循环泵,如果距离近的话水烧热后利用热水上流冷水回流的原理会自动完成循环。…

前言技术之mybatis-plus

目录 1.什么是mybatis-plus 2.初体验 3.日志 4.主键生成策略 5.更新 6.自动填充 1.什么是mybatis-plus 升级版的mybatis&#xff0c;目的是让mybatis更易于使用&#xff0c; 用官方的话说“为简化而生” 官网&#xff1a; MyBatis-Plus 2.初体验 1.准备数据库脚本 数据…

BI 解决方案:BimlStudio 22.3.0 Crack

全功能开发环境&#xff1a;&#xff1a;&#xff1a;&#xff1a; 导入现有解决方案 通过添加 BimlScript 自动化进行更改并重新生成包;使您的解决方案更好、更快。 可视化整个 BI 解决方案 通过我们的可视化设计器在一个位置进行更改&#xff0c;观察您的整个解决方案自行更新…

【ArcGIS微课1000例】0061:ArcGIS打开xyz格式点云数据的方法

本文讲述ArcMap和ArcScene中如何打开xyz格式的点云数据并做可视化的方法。 文章目录 一、xyz格式点云简介二、ArcMap打开xyz点云三、ArcScene打开xyz点云四、注意事项一、xyz格式点云简介 本实验使用的数据是配套数据包中的0061.rar,斯坦福大学的点云数据,格式为X,Y,Z,如下…

【My Electronic Notes系列——晶闸管】

目录 序言&#xff1a; &#x1f3ee;&#x1f3ee;新年的钟声响&#xff0c;新年的脚步迈&#xff0c;祝新年的钟声&#xff0c;敲响你心中快乐的音符&#xff0c;幸运与平安&#xff0c;如春天的脚步紧紧相随&#xff0c;春节快乐&#xff01;春华秋实&#xff0c;我永远与你…

Linux下动静态库的打包与使用C C++

目录前言为什么用动静态库动态链接与静态链接底层优缺点Linux下的动静态库动静态库的对比打包静态库使用静态库打包动态库使用动态库小结win下打包动静态库前言 为什么用动静态库 我们在实际开发中&#xff0c;经常要使用别人已经实现好的功能&#xff0c;这是为了开发效率和…

移动窗口下的LiDAR点云区域生长滤波算法教程

一、前言LiDAR 滤波的现有方法包括&#xff1a;数学形态学滤波法、基于地形坡度滤波、最小二乘内插法滤波等滤波方法。最小二乘内插法能够较好的获取地形趋势面&#xff0c;但是算法中无法根据地形自适应设置参数&#xff1b;在地形起伏较大的地区提取结果精度低&#xff1b;无…

Linux进程的后台运行

文章目录一. 什么是进程?二. 进程后台运行在了解三种进程后台运行的方式前&#xff0c;小编觉得有必要先简单讲解一下什么是进程。 PS: 本篇博客技术参考价值不大&#xff0c;只是类似随笔比较水&#xff0c;详细的知识点可以关注一下nohup命令的使用。 一. 什么是进程? 什…

00开篇词:带你玩转gRPC框架

前言 大家好&#xff0c;先做一下自我介绍 我叫Barry Yan&#xff0c;目前是一名互联网公司的研发工程师&#xff0c;同时也是后端技术领域的狂热爱好者和技术博主&#xff0c;在GitHub、CSDN社区、51CTO博客社区、阿里云技术社区、掘金技术社区和InfoQ写作社区等都有自己的博…

详解1242:网线主管(二分答案经典习题)

题目1242&#xff1a;网线主管时间限制: 1000 ms 内存限制: 65536 KB提交数: 23180 通过数: 5566【题目描述】仙境的居民们决定举办一场程序设计区域赛。裁判委员会完全由自愿组成&#xff0c;他们承诺要组织一次史上最公正的比赛。他们决定将选手的电脑用星形拓扑结构连接在一…

【SVM原理推导】核SVM为什么能分类非线性问题?

核SVM为什么能分类非线性问题?要解决这个问题,首先应该先深入理解SVM的原理与本质。(涉及SVM的问题是很常见的,因为SVM可以算是传统机器学习领域非常成功的算法之一了,现在仍有许多research运用SVM解决问题。) 一、支持向量机(SVM) 1. 基本介绍与提出背景 支持向量机…

【C++】lambda 表达式 | 包装器

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;lambda表…

解决宏碁非凡S3 安装Win11时无法找到驱动器问题

1 问题描述 机型&#xff1a;宏碁非凡S3 2022款CPU&#xff1a;i5 1240P安装系统&#xff1a;Win11 专业版问题描述&#xff1a;安装系统时&#xff0c;在选择驱动器界面无法找到驱动器&#xff0c;如下图所示 2 解决流程 查了一下网上的解决办法&#xff0c;进入BIOS把VMD C…

非极大值抑制(Non-Maximum Suppression)

文章目录一、什么是非极大值抑制二、为什么要用非极大值抑制三、 如何使用非极大值抑制四、代码段一、什么是非极大值抑制 非极大值抑制&#xff0c;简称为NMS算法&#xff0c;英文为Non-Maximum Suppression。其思想是搜素局部最大值&#xff0c;抑制非极大值。NMS算法在不同…