2024-08-26

报错解释:

java.security.NoSuchAlgorithmException 异常表示请求的加密算法在 Java 平台的安全提供者中不存在。这通常发生在尝试实例化一个不支持或未正确安装的加密算法的时候。

解决方法:

  1. 确认算法名称是否正确:检查你尝试实例化的算法名称是否拼写正确,是否与 Java 标准中定义的算法名称一致。
  2. 检查安全策略文件:如果算法名称正确,检查 Java 安全策略文件(通常是 java.policy 或者自定义的策略文件),确保没有禁止使用该算法。
  3. 确认提供者:确保你尝试使用的算法由已注册的安全提供者支持。可以通过 Security.getProviders() 方法查看所有注册的提供者。
  4. 安装或更新安全提供者:如果确认需要的算法应该由某个特定的提供者支持,但该提供者没有被安装或者不是最新的,可以下载并安装最新的提供者或者通过 Java 控制面板安装。
  5. 更新 Java 版本:如果是 Java 平台的问题,尝试更新到最新的 Java 版本,以便获取最新的安全特性和修复。
  6. 代码修正:如果算法名称正确,且没有相关的安全策略限制,可能是代码中的某个地方拼写错误或逻辑错误,仔细检查相关代码段。

在实施以上解决方法时,请确保对系统的改动不会影响其他依赖的组件或应用程序。如果不确定,可以先在测试环境中进行尝试。

2024-08-26



public class DistanceCalculator {
 
    // 方法1:经纬度转换成弧度,然后使用Haversine公式计算距离
    public static double calculateDistanceUsingHaversine(double lat1, double lon1, double lat2, double lon2) {
        int R = 6371; // 地球平均半径,单位为公里
        double phi1 = Math.toRadians(lat1);
        double phi2 = Math.toRadians(lat2);
        double lambda1 = Math.toRadians(lon1);
        double lambda2 = Math.toRadians(lon2);
 
        double a = Math.sin(phi1) * Math.sin(phi2) + Math.cos(phi1) * Math.cos(phi2) * Math.cos(lambda2 - lambda1);
        double distance = R * Math.acos(Math.min(a, 1.0)); // 防止极值
 
        return distance;
    }
 
    // 方法2:使用Vincenty公式计算距离
    // 省略,因为公式复杂且不符合简洁要求
 
    // 方法3:使用Apache Commons库中的DistanceCalculator计算距离
    // 省略,因为需要外部库支持,不符合“不使用任何外部库”的要求
 
    // 方法4:使用Google Maps API计算距离
    // 省略,因为需要网络请求,不符合“不使用网络请求”的要求
 
    // 方法5:使用Java中的GeoAPI库计算距离
    // 省略,因为需要外部库支持,不符合“不使用任何外部库”的要求
 
    // 方法6:使用PostgreSQL中的PostGIS扩展进行距离计算
    // 省略,因为需要数据库支持,不符合“不使用数据库”的要求
 
    // 方法7:使用JavaScript的OpenLocationCode库进行编码和解码
    // 省略,因为是JavaScript代码,不符合“仅使用Java语言”的要求
 
    // 方法8:使用Python的GeoPy库进行距离计算
    // 省略,因为是Python代码,不符合“仅使用Java语言”的要求
 
    // 方法9:使用Scala的GeoTrellis库进行距离计算
    // 省略,因为是Scala代码,不符合“仅使用Java语言”的要求
 
    // 方法10:使用Ruby的Geocoder库进行距离计算
    // 省略,因为是Ruby代码,不符合“仅使用Java语言”的要求
 
    // 以上方法均不符合要求,因此不能作为验证通过的解决方案提供。
}

以上代码示例均不能作为验证通过的解决方案提供,因为它们使用了不符合要求的方法或编程语言。需要注意的是,问题中要求的是一个使用Java语言的解决方案,并且不能使用外部库、网络请求、数据库或其他编程语言。因此,上述所有示例都不能作为有效的解决方案提供。

2024-08-26



public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}
 
public class LinkedListAlgorithm {
 
    // 判断回文链表
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null) {
            return true;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode secondHead = reverseList(slow.next);
        ListNode p1 = head;
        ListNode p2 = secondHead;
        while (p2 != null) {
            if (p1.val != p2.val) {
                return false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }
        return true;
    }
 
    // 反转链表
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode nextTemp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = nextTemp;
        }
        return prev;
    }
 
    // 判断链表是否有环,并找出环入口
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while (fast != slow) {
            if (fast.next == null || fast.next.next == null) {
                return null;
            }
            fast = fast.next.next;
            slow = slow.next;
        }
        fast = head;
        while (fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }
}

这段代码首先定义了一个简单的链表节点类ListNode,然后在LinkedListAlgorithm类中实现了判断回文链表、反转链表以及判断链表是否有环并找出环入口的算法。这些算法是链表问题中的经典算法,对于学习数据结构和算法有重要的教育意义。

2024-08-26



import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.concurrent.atomic.AtomicLong;
 
public class SnowflakeIdWorker {
 
    // 初始时间戳
    private final static long INITIAL_TIMESTAMP = 1640995200000L; // 假设的初始时间戳
 
    // 机器ID所占的位数
    private final static long ID_BITS = 5L;
    // 数据中心ID所占的位数
    private final static long DATA_CENTER_ID_BITS = 5L;
 
    // 机器ID最大值
    private final static long MAX_MACHINE_ID = -1L ^ (-1L << ID_BITS);
    // 数据中心ID最大值
    private final static long MAX_DATA_CENTER_ID = -1L ^ (-1L << DATA_CENTER_ID_BITS);
 
    // 序列在ID中的位置
    private final static long SEQUENCE_BITS = 12L;
 
    // 机器ID偏左移12位
    private final static long MACHINE_ID_LEFT = SEQUENCE_BITS;
    // 数据中心ID偏左移17位
    private final static long DATA_CENTER_ID_LEFT = SEQUENCE_BITS + ID_BITS;
    // 时间戳偏左移22位
    private final static long TIMESTAMP_LEFT = SEQUENCE_BITS + ID_BITS + DATA_CENTER_ID_BITS;
 
    // 序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
    private final static long SEQUENCE_MASK = -1L ^ (-1L << SEQUENCE_BITS);
 
    // 工作机器ID(0~31)
    private long machineId;
    // 数据中心ID(0~31)
    private long dataCenterId;
    // 下一个序列值
    private AtomicLong sequence = new AtomicLong(0L);
    // 上次生成ID的时间戳
    private long lastTimestamp = -1L;
 
    public SnowflakeIdWorker(long machineId, long dataCenterId) {
        if (machineId > MAX_MACHINE_ID || machineId < 0) {
            throw new IllegalArgumentException("机器ID超出范围");
        }
        if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
            throw new IllegalArgumentException("数据中心ID超出范围");
        }
        this.machineId = machineId;
        this.dataCenterId = dataCenterId;
    }
 
    /**
     * 创建一个新的ID
     *
     * @return Snowflake生成的ID
     */
    public synchronized long nextId() {
        long timestamp = timeGen();
 
        // 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退了,这是不允许的。
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format(
                    "时钟回退,上一个ID生成的时间戳为:%d,现在时间戳为:%d", lastTimestamp, timestamp));
        }
 
        // 如果是同一时间生成的,则进行序列号的自增
        if (lastTimestamp == timestamp) {
2024-08-26

二分查找算法通常用于在有序数组中查找特定元素。以下是使用Python、Java和C++实现的二分查找算法的示例代码。

Python:




def binary_search(arr, x):
    low = 0
    high = len(arr) - 1
    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == x:
            return mid
        elif arr[mid] > x:
            high = mid - 1
        else:
            low = mid + 1
    return -1
 
# 示例使用
arr = [2, 3, 4, 10, 40]
x = 10
 
# 函数调用
result = binary_search(arr, x)
print(result)  # 输出元素的索引,未找到返回-1

Java:




public class BinarySearch {
    public static int binarySearch(int[] arr, int x) {
        int low = 0;
        int high = arr.length - 1;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (arr[mid] == x) {
                return mid;
            } else if (arr[mid] > x) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return -1;
    }
 
    // 示例使用
    public static void main(String[] args) {
        int[] arr = {2, 3, 4, 10, 40};
        int x = 10;
 
        // 函数调用
        int result = binarySearch(arr, x);
        System.out.println(result);  // 输出元素的索引,未找到返回-1
    }
}

C++:




#include <iostream>
#include <vector>
 
int binarySearch(const std::vector<int>& arr, int x) {
    int low = 0;
    int high = arr.size() - 1;
    while (low <= high) {
        int mid = (low + high) / 2;
        if (arr[mid] == x) {
            return mid;
        } else if (arr[mid] > x) {
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return -1;
}
 
int main() {
    std::vector<int> arr = {2, 3, 4, 10, 40};
    int x = 10;
 
    // 函数调用
    int result = binarySearch(arr, x);
    std::cout << result << std::endl;  // 输出元素的索引,未找到返回-1
    return 0;
}

以上代码实现了二分查找算法,在有序数组中查找特定元素的索引。如果找到,返回元素的索引;如果未找到,返回-1。

2024-08-26



public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}
 
public class LinkedListAlgorithm {
 
    // 删除有序链表中值相同的节点
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) {
            return head;
        }
        ListNode current = head;
        while (current.next != null) {
            if (current.val == current.next.val) {
                current.next = current.next.next;
            } else {
                current = current.next;
            }
        }
        return head;
    }
 
    // 合并两个有序链表
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) {
            return l2;
        } else if (l2 == null) {
            return l1;
        }
        ListNode dummy = new ListNode(0);
        ListNode current = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                current.next = l1;
                l1 = l1.next;
            } else {
                current.next = l2;
                l2 = l2.next;
            }
            current = current.next;
        }
        if (l1 != null) {
            current.next = l1;
        }
        if (l2 != null) {
            current.next = l2;
        }
        return dummy.next;
    }
 
    // 合并k个有序链表
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        ListNode dummy = new ListNode(0);
        ListNode current = dummy;
        PriorityQueue<ListNode> pq = new PriorityQueue<>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });
        for (ListNode head : lists) {
            if (head != null) {
                pq.add(head);
            }
        }
        while (!pq.isEmpty()) {
            ListNode
2024-08-26

以下是插入排序、希尔排序、选择排序和堆排序的Java实现示例代码:




// 插入排序
public void insertionSort(int[] arr) {
    for (int i = 1; i < arr.length; i++) {
        int key = arr[i];
        int j = i - 1;
 
        // 移动元素
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}
 
// 希尔排序
public void shellSort(int[] arr) {
    int n = arr.length;
    int h = 1;
    while (h < n / 3) {
        h = h * 3 + 1;
    }
 
    while (h >= 1) {
        for (int i = h; i < n; i++) {
            int temp = arr[i];
            int j = i;
            while (j >= h && arr[j - h] > temp) {
                arr[j] = arr[j - h];
                j = j - h;
            }
            arr[j] = temp;
        }
        h = h / 3;
    }
}
 
// 选择排序
public void selectionSort(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        int temp = arr[minIndex];
        arr[minIndex] = arr[i];
        arr[i] = temp;
    }
}
 
// 堆排序
public void heapSort(int[] arr) {
    int n = arr.length;
 
    // Build heap (rearrange array)
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(arr, n, i);
    }
 
    // One by one extract elements
    for (int i = n - 1; i >= 0; i--) {
        // Move current root to end
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
 
        // heapify the root element
        heapify(arr, i, 0);
    }
}
 
private void heapify(int[] arr, int n, int i) {
    int largest = i; // Initialize largest as root
    int l = 2 * i + 1; // left = 2*i + 1
    int r = 2 * i + 2; // right = 2*i + 2
 
    // If left child is larger than root
    if (l < n && arr[l] > arr[largest]) {
        largest = l;
    }
 
    // If right child is larger than largest so far
    if (r < n && arr[r] > arr[largest]) {
        largest = r;
    }
 
    // If largest is not root
    if (largest != i) {
        int swap = arr[i];
        arr[i] = arr[largest];
        arr[largest] = swap;
 
        // Recursively heapify the affected sub-tree
        heapify(arr, n, largest);
    }
}
2024-08-26

冒泡排序、快速排序、归并排序和堆排序是四种常用的排序算法,以下是它们的Java实现:

冒泡排序:




public void bubbleSort(int[] arr) {
    int n = arr.length;
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                // 交换 arr[j+1] 和 arr[j]
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

快速排序:




public void quickSort(int[] arr, int low, int high) {
    if (low < high) {
        // 获取分区后的枢纽位置
        int pivotIndex = partition(arr, low, high);
 
        // 分别对枢纽左右两边进行递归排序
        quickSort(arr, low, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, high);
    }
}
 
// 分区函数
private int partition(int[] arr, int low, int high) {
    // 选择一个枢纽元素,这里选择最高位作为枢纽
    int pivot = arr[high];
    int i = (low - 1);
    
    // 遍历数组,将小于枢纽的元素放到左边,大于枢纽的元素放到右边
    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
 
            // 交换 arr[i] 和 arr[j]
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
 
    // 将枢纽元素放到正确的位置
    int temp = arr[i + 1];
    arr[i + 1] = arr[high];
    arr[high] = temp;
 
    return i + 1;
}

归并排序:




public void mergeSort(int[] arr, int low, int high) {
    if (low < high) {
        // 找到中间索引
        int mid = (low + high) / 2;
 
        // 对左边进行递归排序
        mergeSort(arr, low, mid);
 
        // 对右边进行递归排序
        mergeSort(arr, mid + 1, high);
 
        // 合并两个已排序的子数组
        merge(arr, low, mid, high);
    }
}
 
// 合并两个已排序的子数组
private void merge(int[] arr, int low, int mid, int high) {
    // 创建一个临时数组
    int[] temp = new int[high - low + 1];
    int i = low;
    int j = mid + 1;
    int k = 0;
 
    // 比较两个子数组,并将较小的元素放入临时数组中
    while (i <= mid && j <= high) {
        if (arr[i] <= arr[j]) {
            temp[k++] = arr[i++];
        } else {
            temp[k++]
2024-08-26



public class SortAlgorithms {
 
    // 交换数组中的两个元素
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
 
    // 直接插入排序
    public static void insertionSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            for (int j = i; j > 0; j--) {
                if (arr[j] < arr[j - 1]) {
                    swap(arr, j, j - 1);
                }
            }
        }
    }
 
    // 冒泡排序
    public static void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                }
            }
        }
    }
 
    // 选择排序
    public static void selectionSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            swap(arr, i, minIndex);
        }
    }
 
    // 快速排序
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            // 获取分区后的枢纽位置
            int pivotIndex = partition(arr, low, high);
            
            // 分别对枢纽左右两边进行递归排序
            quickSort(arr, low, pivotIndex - 1);
            quickSort(arr, pivotIndex + 1, high);
        }
    }
 
    private static int partition(int[] arr, int low, int high) {
        // 选择一个枢纽元素,这里选择最高位作为枢纽
        int pivot = arr[high];
        int i = (low - 1);
        
        // 遍历数组,将小于枢纽的元素放到左边,大于枢纽的元素放到右边
        for (int j = low; j < high; j++) {
            if (arr[j] < pivot) {
                i++;
 
                // 交换 arr[i] 和 arr[j]
                swap(arr, i, j);
            }
        }
        
        // 最后将枢纽元素放到正确的位置
        swap(arr, i + 1, high);
        
        return i + 1;
    }
 
    // 归并排序
    public static void mergeSort(int[] arr) {
        int mid = arr.length / 2;
        if (arr.length >= 2) {
            // 分割数组
            int[] leftHalf = Arrays.copyOfRange(arr, 0, mid);
            int[] rightHalf = Arrays.copyOfRange(arr, mid, arr.length);
 
            // 递归分割
            mergeSort(leftHalf);
            mergeSort(rightHalf);
 
            // 合并数组
  
2024-08-26

以下是实现单链表反转的 5 种方法的示例代码:

  1. 递归反转



public ListNode reverseList(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    ListNode p = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return p;
}
  1. 迭代反转



public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode curr = head;
    while (curr != null) {
        ListNode nextTemp = curr.next;
        curr.next = prev;
        prev = curr;
        curr = nextTemp;
    }
    return prev;
}
  1. 交换节点反转



public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode curr = head;
    while (curr != null) {
        ListNode nextTemp = curr.next; // Temporarily store the next node
        curr.next = prev; // Reverse the link
        prev = curr; // Move forward on the list
        curr = nextTemp; // Move forward on the list
    }
    return prev;
}
  1. 使用栈



public ListNode reverseList(ListNode head) {
    Deque<ListNode> stack = new LinkedList<>();
    ListNode current = head;
    while (current != null) {
        stack.push(current);
        current = current.next;
    }
    current = stack.poll();
    ListNode newHead = current;
    while (!stack.isEmpty()) {
        current.next = stack.poll();
        current = current.next;
    }
    current.next = null;
    return newHead;
}
  1. 使用头插法



public ListNode reverseList(ListNode head) {
    ListNode newHead = null;
    while (head != null) {
        ListNode next = head.next; // Temporarily store the next node
        head.next = newHead; // Reverse the link
        newHead = head; // Move forward on the list
        head = next; // Move forward on the list
    }
    return newHead;
}

以上每种方法都是单链表反转的有效方式,选择合适的方法取决于特定的应用场景和性能要求。