算法联系题

1.定义一个数组,使用选择排序对数组进行排序

1.1选择排序

public class Hello1 {
    public static void main(String[] args) {
 int arr [] ={1,90,56,123,9,8,6,7,2,8,1};
        for (int i = 0; i <arr.length-1 ; i++) {
            int minIndex=i;//最小下标默认值
            //1.从i到len-1这个范围中找最小值下标
            for (int j = i; j <=arr.length-1 ; j++) {
                if (arr[j]<arr[minIndex]){
                    minIndex=j;
                }
            }
            //2.交换元素
            int t=arr[i];
            arr[i]=arr[minIndex];
            arr[minIndex]=t;

        }
        //输出数组
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
    }
}

1.2 快速排序

import java.util.Arrays;

public class TestBubble {
    public static void main(String[] args) {
        fun3();
    }

    private static void fun3() {
        int arr []={8,5,0,1,4};
        int[] arr2 = quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr2));
    }
    // 快 速
    private static int [] quickSort(int arr[],int l,int r) {
        int X=arr[l];
        int i=l,j=r;
        while (i<j){
            //从右向左,找出比X小的数的下标 j
            while (i<j &&arr[j]>X){
                j--;
            }
            //从左向右,找出比X大的数的下标
            while (i<j &&arr[i]<X){
                i++;
            }
            if(arr[i]==arr[j]&&i<j){
                i++;
            }else {
                int t=arr[i];
                arr[i]=arr[j];
                arr[j]=t;
            }
        }
        if(i-1>l){
            arr=quickSort(arr,l,i-1);
        }
        if(j+1<r){
            arr=quickSort(arr,j+1,r);
        }
        return arr;
    }
}

1.3冒泡排序

public class Hello1 {
    public static void main(String[] args) {
        int arr[]={9,4,5,6,8,1,40};
        for (int i = 1; i <=arr.length-1; i++) {
            for (int j = 0; j <=arr.length-i-1; j++) {
                if (arr[j]>arr[j+1]){
                    int t=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=t;
                }
            }
        }
        //输出数组
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
    }
}

2.定义一个字符串,统计其中字符的个数

	static void test_4() {
		
		/*
		 * 统计字符串中每个字符的个数
		 * 例如 字符串 为 aabb112, 输出为a()b()1()2(),2()
		 * 
		 * a="ssddsdfsadfs";
		 * 获取第0个字符,遍历和其余字符串比较  相等  加1
		 * b = a(2)
		 * a ="bb";
		 * 获取第0个字符,遍历和其余字符串比较  相等  加1
		 *  b = a(2)b(2);
		 *  a=""
		 */
		String  a= "j   aakethehoworkfang ,,, ";
		String b = "";
		while(a.length() > 0) {
			//统计字符个数
			int sum =1;
			//获取需要被统计个数的字符
			char ch = a.charAt(0);
			for(int i = 1; i<a.length();i++) {
				char c =a.charAt(i);
				if(ch ==c) {
					sum ++;	
				}
			}
			//ch统计完成
			b = b + ch + "(" + sum +")";
			//将统计过的替换掉
			a = a.replace(ch+"","");
		}
		System.out.println(b);
	}

3.现在有两个文件a.txt和b.txt,其中有一些单词,单词都是以空格隔开;要求:将a和b中的所有单词交替合并到c.txt中

4.定义一个方法,可以对目录进行拷贝

// 3.定义一个方法,可以拷贝文件夹
   /**
    * 拷贝文件夹的方法
    * @param srcPath 源文件夹的路径
    * @param desPath 目标文件夹的上一级路径
    * @return  如果拷贝成功返回true,反之返回false
    * @throws IOException
    */
   static boolean copyFile(String srcPath, String desPath) throws IOException {
   	// 源文件夹
   	File srcFile = new File(srcPath);
   	if(!srcFile.exists() || !srcFile.isDirectory()) {
   		// 说明源文件夹为空或者文件夹不存在
   		throw new FileNotFoundException("源文件夹不存在或者源文件夹不是文件夹!");
   	}
   	// 得到源文件夹的名字
   	String name = srcFile.getName();
   	
   	// 目标文件夹的上一级目标路径
   	File desFile = new File(desPath);
   	if(!desFile.exists() || !desFile.isDirectory()) {
   		throw new FileNotFoundException("目标文件夹父路径不存在或者不是一个文件夹!");
   	}
   	// 目标文件夹
   	String item = desPath;
   	
   	desPath = item + "\\" + name;
   	desFile = new File(desPath);
   	desFile.mkdir();
   	
   	if(desFile.getPath().equals(srcFile.getPath())) {
   		throw new FileNotFoundException("在同一个目标文件夹下,不能拷贝!");
   	}
   	// 说明可以拷贝了  逐个拷贝里面的文件
   	File[] subFiles = srcFile.listFiles();
   	String temp = srcPath;
   	//System.out.println("temp = " + temp);
   	for(File sub : subFiles) {
   		if(sub.isFile()) {
   			// 说明sub是文件,直接拷贝文件
   			srcPath = temp + "\\" + sub.getName();
   			
   			//System.out.println("文件srcPath =" + srcPath);
   			copy(srcPath, desPath);
   		}else {
   			srcPath = temp + "\\" + sub.getName();
   			//System.out.println("srcPath = " + srcPath);
   			//System.out.println("desPath = " + desPath);
   			copyFile(srcPath, desPath);
   		}
   	}
   	return true;
   	
   }

5.现有一个双向链表,判断该链表是否是回文

1.方法1:将链表元素都赋值到数组中,然后可以从数组两端向中间对比。主要是在while循环中pre.next = prepre;和prepre = pre;实现了一边遍历一遍将访问过的链表给反转了,所以理解起来有些难度,

快慢指针法

public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null) {
            return true;
        }
        ListNode slow = head, fast = head;
        ListNode pre = head, prepre = null;
        while(fast != null && fast.next != null) {
            pre = slow;
            slow = slow.next;
            fast = fast.next.next;
            //将前半部分链表反转
            pre.next = prepre;
            prepre = pre;
        }
        if(fast != null) {
            slow = slow.next;
        }
        while(pre != null && slow != null) {
            if(pre.val != slow.val) {
                return false;
            }
            pre = pre.next;
            slow = slow.next;
        }
        return true;
    }
  1. ​ 使用栈:全部压栈

    public boolean isPalindrome(ListNode head) {
        ListNode temp = head;
        Stack<Integer> stack = new Stack();
        //把链表节点的值存放到栈中
        while (temp != null) {
            stack.push(temp.val);
            temp = temp.next;
        }
        //然后再出栈
        while (head != null) {
            if (head.val != stack.pop()) {
                return false;
            }
            head = head.next;
        }
        return true;
    }
    

3.使用栈:部分压栈

改造上面的方法,先遍历第一遍,得到总长度。之后一遍历链表,一遍压栈。当到达链表长度一半的位置之后,就不再压栈,而是一边出栈,一遍遍历,一遍比较,只要有一个不相等,就不是回文链表。代码就是这样:

public boolean isPalindrome(ListNode head) {
    if (head == null)
        return true;
    ListNode temp = head;
    Stack<Integer> stack = new Stack();
    //链表的长度
    int len = 0;
    //把链表节点的值存放到栈中
    while (temp != null) {
        stack.push(temp.val);
        temp = temp.next;
        len++;
    }
    //len长度除以2
    len >>= 1;
    //然后再出栈
    while (len-- >= 0) {
        if (head.val != stack.pop())
            return false;
        head = head.next;
    }
    return true;
}

6.一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶,求该青蛙跳上n级台阶总共有多少中跳法

解题思路🍖
若n为1级台阶:f(1) = 1 (只可能有一种跳法)
若n为2级台阶:f(2) = f(2 - 1) + f(2 - 2)(会有两个跳得方式,一次1阶或者一次2阶)
若n为3级台阶:f(3) = f(3 - 1) + f(3 - 2) + f(3 - 3)(会有三种跳得方式,一次1阶、2阶、3阶)
……
……
若n为(n - 1)级台阶:

f(n-1) = f((n-1)-1) + f((n-1)-2) + … + f((n-1)-(n-2)) + f((n-1)-(n-1))
f(n-1) = f(0) + f(1)+f(2)+f(3) + … + f((n-1)-1)
f(n-1) = f(0) + f(1) + f(2) + f(3) + … + f(n-2)

若n为n级台阶:

f(n) = f(n-1) + f(n-2) + f(n-3) + … + f(n-(n-1)) + f(n-n)
f(n) = f(0) + f(1) + f(2) + f(3) + … + f(n-2) + f(n-1)

结合f(n-1)和f(n)的情况你会发现f(n) = f(n-1) + f(n-1),所以可得: f(n) = 2*f(n-1)。

7.有多个有序的list集合,将这多个集合合并为一个集合,和并之后的集合也要保证有序

在Java中,你可以使用优先队列(PriorityQueue)来合并多个有序列表,同时保持结果有序。以下是一个示例代码,演示如何合并多个有序列表:

```java
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;

public class MergeSortedLists {
    public static List<Integer> mergeSortedLists(List<List<Integer>> lists) {
        List<Integer> result = new ArrayList<>();
        PriorityQueue<Pair> minHeap = new PriorityQueue<>((a, b) -> a.value - b.value);

        // 初始化优先队列,将每个列表的第一个元素加入队列
        for (int i = 0; i < lists.size(); i++) {
            if (!lists.get(i).isEmpty()) {
                minHeap.offer(new Pair(i, 0, lists.get(i).get(0)));
            }
        }

        while (!minHeap.isEmpty()) {
            Pair pair = minHeap.poll();
            int listIndex = pair.listIndex;
            int elementIndex = pair.elementIndex;

            // 添加当前最小元素到结果列表
            result.add(pair.value);

            // 移动到下一个元素
            elementIndex++;
            if (elementIndex < lists.get(listIndex).size()) {
                minHeap.offer(new Pair(listIndex, elementIndex, lists.get(listIndex).get(elementIndex)));
            }
        }

        return result;
    }

    static class Pair {
        int listIndex;
        int elementIndex;
        int value;

        Pair(int listIndex, int elementIndex, int value) {
            this.listIndex = listIndex;
            this.elementIndex = elementIndex;
            this.value = value;
        }
    }

    public static void main(String[] args) {
        List<List<Integer>> lists = new ArrayList<>();
        lists.add(List.of(1, 3, 5));
        lists.add(List.of(2, 4, 6));
        lists.add(List.of(0, 7, 8));

        List<Integer> result = mergeSortedLists(lists);
        System.out.println(result);  // 输出 [0, 1, 2, 3, 4, 5, 6, 7, 8]
    }
}
```

这段Java代码使用优先队列(最小堆)来维护多个列表的当前元素,并不断选择最小的元素添加到结果列表中。这种方法的时间复杂度为 O(NlogK),其中 N 是所有元素的总数,K 是列表的数量。它能够有效地合并多个有序列表并保持结果有序。
要将多个有序的列表合并成一个有序的列表,可以使用归并排序的思想。以下是一个示例的Java代码实现:
import java.util.ArrayList;
import java.util.List;
 public class MergeSortedLists {
    public static void main(String[] args) {
        List<Integer> list1 = List.of(1, 3, 5, 7);
        List<Integer> list2 = List.of(2, 4, 6, 8);
        List<Integer> list3 = List.of(0, 9, 10);
         List<Integer> mergedList = mergeSortedLists(list1, list2, list3);
        System.out.println("Merged List: " + mergedList);
    }
     public static List<Integer> mergeSortedLists(List<Integer>... lists) {
        List<Integer> mergedList = new ArrayList<>();
         // Initialize pointers for each list
        int[] pointers = new int[lists.length];
         // Merge lists until all elements are processed
        while (true) {
            // Find the smallest element among the current pointers
            int smallest = Integer.MAX_VALUE;
            int smallestListIndex = -1;
            for (int i = 0; i < lists.length; i++) {
                List<Integer> list = lists[i];
                int pointer = pointers[i];
                if (pointer < list.size() && list.get(pointer) < smallest) {
                    smallest = list.get(pointer);
                    smallestListIndex = i;
                }
            }
             // If all pointers have reached the end, break the loop
            if (smallestListIndex == -1) {
                break;
            }
             // Add the smallest element to the merged list
            mergedList.add(smallest);
             // Move the pointer of the list that contains the smallest element
            pointers[smallestListIndex]++;
        }
         return mergedList;
    }
}
在上述示例中,我们有三个有序列表 list1 、 list2 、 list3 。我们使用 mergeSortedLists 方法将这三个列表合并成一个有序的列表 mergedList 。最后,我们将合并后的列表打印到控制台上。 输出结果:
Merged List: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
注意:在示例中,我们假设输入的列表已经是有序的。如果输入的列表不是有序的,你可以在合并之前先对每个列表进行排序。

8.定义两个线程,交替打印奇偶数

场景一:线程A打印奇数,线程B打印偶数,线程A和线程B交替打印,使用对象监视器实现。线程A和线程B交替打印奇数和偶数,使用对象监视器实现,通俗来说:线程A或线程B只要有一者竞争锁成功,就打印++i,通知其他线程从等待集合中释放,然后自身线程加入等待集合并且释放锁即可。

public class OddEvenPrinter {

   private final Object monitor = new Object();
   private final int limit;
   private volatile int count;

   public OddEvenPrinter(int limit, int initCount) {
       this.limit = limit;
       this.count = initCount;
   }

   public void print() {
       synchronized (monitor) {
           while (count < limit) {
               try {
                   System.out.println(String.format("线程[%s]打印数字:%d", Thread.currentThread().getName(), ++count));
                   monitor.notifyAll();
                   monitor.wait();
               } catch (InterruptedException e) {
                   //ignore
               }
           }
       }
   }

   public static void main(String[] args) throws Exception {
       OddEvenPrinter printer = new OddEvenPrinter(10, 0);
       Thread thread1 = new Thread(printer::print, "thread-1");
       Thread thread2 = new Thread(printer::print, "thread-2");
       thread1.start();
       thread2.start();
       Thread.sleep(Integer.MAX_VALUE);
   }
}

场景二:线程A打印奇数,线程B打印偶数,线程A和线程B交替打印,使用JDK提供的并发类库实现。如果需要使用JUC中提供的并发类库,可以考虑和对象监视器功能接近的可重入锁ReentrantLock

public class OddEvenPrinterEx {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    private final int limit;
    private volatile int count;

    public OddEvenPrinterEx(int limit, int initCount) {
        this.limit = limit;
        this.count = initCount;
    }

    public void print()  {
        lock.lock();
        try {
           while (count < limit){
               System.out.println(String.format("线程[%s]打印数字:%d", Thread.currentThread().getName(), ++count));
               condition.signalAll();
               try {
                   condition.await();
               } catch (InterruptedException e) {
                   //ignore
               }
           }
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws Exception {
        OddEvenPrinterEx printer = new OddEvenPrinterEx(10, 0);
        Thread thread1 = new Thread(printer::print, "thread-1");
        Thread thread2 = new Thread(printer::print, "thread-2");
        thread1.start();
        thread2.start();
        Thread.sleep(Integer.MAX_VALUE);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值