public static ListNode swapByNodes(ListNode head, int val1, int val2) {
        if (head == null || val1 == val2) return head;
        
        // Find nodes with val1 and val2, and their previous nodes
        ListNode prev1 = null, curr1 = head;
        ListNode prev2 = null, curr2 = head;
        
        // Find first node with val1
        while (curr1 != null && curr1.val != val1) {
            prev1 = curr1;
            curr1 = curr1.next;
        }
        
        // Find first node with val2
        while (curr2 != null && curr2.val != val2) {
            prev2 = curr2;
            curr2 = curr2.next;
        }
        
        // If either value is not found, return original list
        if (curr1 == null || curr2 == null) return head;
        
        // If prev1 is null, curr1 is the head
        if (prev1 != null) {
            prev1.next = curr2;
        } else {
            head = curr2;
        }
        
        // If prev2 is null, curr2 is the head
        if (prev2 != null) {
            prev2.next = curr1;
        } else {
            head = curr1;
        }
        
        // Swap next pointers
        ListNode temp = curr1.next;
        curr1.next = curr2.next;
        curr2.next = temp;
        
        return head;
    }